4

我正在尝试将 Google 测试 ( gtest ) 代码移植到 VxWorks 5.5。严重的缺点是开发环境 Tornado 2.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应包含答案。为了得到答案,使用了两个私有函数,并且. 但是这两个函数只在这里声明,我找不到它们的定义。如果不出意外,此实现不应链接。FromToMakeFrom()Helper()

我也不明白以下的语法

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

当然,这段代码编译得很好(在 Microsoft Visual C++ 7.1 或更高版本或 GCC 3.4 或更高版本下),Google 的人确切地知道他们在做什么。

请赐教!不理解这段代码会让我发疯!:)

4

1 回答 1

11

这是模板编程的标准技巧。

请注意,评论说“通过检查 Helper(x) 的大小”:这强调了代码所做的唯一Helper事情就是评估sizeof(Helper(x))some xsizeof运算符实际上并不评估它的参数(它不需要;它只需要找出它有多大,这可能只使用编译时可用的信息),这就是为什么没有链接器错误(Helper永远真的叫)。

给您带来麻烦的语法意味着该Helper函数接受任意数量和类型的参数并返回对 a 的引用char[2]要为这种类型的函数(可变参数函数)编写签名,需要使用省略号 ( ...) 作为最后一个参数的规范。

可变参数函数是从 C 继承的一个特性,通常应该避免使用,并且在与类类型一起使用时会造成严重破坏,但在这种情况下,它并不重要,因为 - 如前所述 -Helper实际上不会被调用。

该类通过允许您使用语法将这一切联系在一起

ImplicitlyConvertible<From, To>::value

要生成value,代码“伪造”调用并将其作为参数Helper传递给它的实例¹。From它依赖于编译器的重载决议来确定To在这种情况下是否会调用采用 a 的重载;如果是这样,则该重载的返回值char具有保证大小1value最终为true. 否则选择可变参数重载(可以采用任何类型的参数),它返回 a char[2]。这有一个大于1,所以value结束了false


¹ 请注意,这里sizeof再次使用了“实际上并不计算表达式”技巧:你如何告诉编译器参数HelperFrom? 您可以使用From(),但From需要有一个默认的公共构造函数来编译代码。因此,您只需告诉编译器“我有一个MakeFrom返回 aFrom的函数”——该函数实际上不会被调用。

于 2012-09-03T08:59:53.963 回答