这个C++模板类代码是如何工作的

How does this C++ template class code work?

本文关键字:何工作 工作 C++ 代码 这个      更新时间:2023-10-16

我正在尝试将Google Test(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
};

创建此类的对象时,如果模板类型From可隐式转换为模板类型To,则名称为value的布尔变量应包含答案。为了得到答案,使用了两个私有函数MakeFrom()Helper()。但这两个函数只在这里声明,我找不到它们的定义。如果没有其他内容,则此实现不应链接。

我也不理解以下的语法

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

当然,这段代码编译得很好(在Microsoft Visual C++7.1或更新版本或GCC 3.4或更新版本下),谷歌的员工非常清楚他们在做什么。

请开导我!不理解这个代码会让我发疯!:)

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

请注意,注释说"通过检查Helper(x)的大小":这强调了代码对Helper所做的唯一的事情是为某些x计算sizeof(Helper(x))sizeof运算符实际上并不计算其参数(它不需要;它只需要找出它的大小,这可能只使用编译时可用的信息),这就是为什么不存在链接器错误的原因(Helper从未真正被调用)。

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

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

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

ImplicitlyConvertible<From, To>::value

为了生成value,代码"伪造"调用Helper,并将From的实例作为参数1传递给它。它依赖于编译器的重载解析来确定在这种情况下是否会调用使用To的重载;如果是,则该过载的返回值是具有1的保证大小的char,并且value最终是true。否则,会选择变量重载(可以采用任何类型的参数),返回char[2]。它的大小大于1,因此value最终为false


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