4

Google Test(gtest)コードをVxWorks5.5に移植しようとしています。重大な欠点は、開発環境Tornado2.2が古いGCCコンパイラバージョン2.96を使用していることです。

コードを分析しているときに、コードの一部を見つけましたがgtest.hわかりません。このC++テンプレートクラスはどのように機能していますか?

// ImplicitlyConvertible<From, To>::value is a compile-time bool
// constant that's true iff type From can be implicitly converted to
// type To.
template <typename From, typename To>
class ImplicitlyConvertible {
 private:
  // We need the following helper functions only for their types.
  // They have no implementations.

  // MakeFrom() is an expression whose type is From.  We cannot simply
  // use From(), as the type From may not have a public default
  // constructor.
  static From MakeFrom();

  // These two functions are overloaded.  Given an expression
  // Helper(x), the compiler will pick the first version if x can be
  // implicitly converted to type To; otherwise it will pick the
  // second version.
  //
  // The first version returns a value of size 1, and the second
  // version returns a value of size 2.  Therefore, by checking the
  // size of Helper(x), which can be done at compile time, we can tell
  // which version of Helper() is used, and hence whether x can be
  // implicitly converted to type To.
  static char Helper(To);
  static char (&Helper(...))[2];  // NOLINT

  // We have to put the 'public' section after the 'private' section,
  // or MSVC refuses to compile the code.
 public:
  // MSVC warns about implicitly converting from double to int for
  // possible loss of data, so we need to temporarily disable the
  // warning.
#ifdef _MSC_VER
# pragma warning(push)          // Saves the current warning state.
# pragma warning(disable:4244)  // Temporarily disables warning 4244.

  static const bool value =
      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
# pragma warning(pop)           // Restores the warning state.
#elif defined(__BORLANDC__)
  // C++Builder cannot use member overload resolution during template
  // instantiation.  The simplest workaround is to use its C++0x type traits
  // functions (C++Builder 2009 and above only).
  static const bool value = __is_convertible(From, To);
#else
  static const bool value =
      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
#endif  // _MSV_VER
};

このクラスのオブジェクトが作成されるとき、テンプレートタイプが暗黙的にテンプレートタイプに変換可能であるvalue場合、名前のブール変数には答えが含まれている必要があります。答えを得るために、2つのプライベート関数が使用されます。しかし、これら2つの関数はここでのみ宣言されており、どちらの定義も見つかりません。他に何もないとしても、この実装はリンクすべきではありません。FromToMakeFrom()Helper()

次の構文もわかりません

static char (&Helper(...))[2];

もちろん、このコードは(Microsoft Visual C ++7.1以降またはGCC3.4以降では)問題なくコンパイルされ、Googleの担当者は自分たちが何をしているのかを正確に知っています。

教えてください!このコードを理解していないと、私は夢中になります!:)

4

1 に答える 1

11

これは、テンプレートプログラミングの標準的なトリックです。

コメントには「Helper(x)のサイズをチェックすることによって」と書かれていることに注意してください。これは、コードが行うのはいくつかの評価だけであることを強調しています。オペレーターは実際に引数を評価しません(必要はありません。コンパイル時に利用可能な情報のみを使用して可能な、引数の大きさを確認するだけで済みます)。これがリンカーエラーが発生しない理由です(決して評価されません)。本当に呼ばれます)。Helpersizeof(Helper(x))xsizeofHelper

問題を引き起こす構文Helperは、任意の数とタイプのパラメーターを受け入れ、への参照を返す関数であることを意味しますchar[2]。このタイプの関数(可変個引数関数...)の署名を作成するには、最後の引数の指定として省略記号()を使用する必要があります。

可変個引数関数はCから継承された機能であり、一般的に回避する必要があり、クラス型で使用すると大混乱を引き起こしますが、この場合、前述のようHelperに実際には呼び出されないため、問題ではありません。

クラスは、構文を使用できるようにすることで、これをすべて結び付けます

ImplicitlyConvertible<From, To>::value

を生成するために、コードはそれを引数としてのインスタンスを呼び出して渡すことをvalue「偽造」します¹ 。コンパイラの過負荷解決に依存して、このシナリオでaをとる過負荷が呼び出されるかどうかを判断します。その場合、そのオーバーロードの戻り値は、の保証されたサイズを持ち、最終的にはになります。それ以外の場合は、可変個引数のオーバーロード(任意のタイプの引数を取ることができます)が選択され、。が返されます。これは、より大きいサイズであるため、最終的にはになります。HelperFromTochar1valuetruechar[2]1valuefalse


¹ここでは、「sizeof実際には式を評価しない」というトリックが再び使用されていることに注意してください。への引数Helperがのインスタンスであることをコンパイラにどのように伝えますFromか?を使用することもできますFrom()From、コードをコンパイルするには、デフォルトのパブリックコンストラクターが必要になります。MakeFromしたがって、コンパイラに「「を返す関数があります」と伝えるだけですFrom。関数は実際には呼び出されません。

于 2012-09-03T08:59:53.963 に答える