这个C++模板类代码是如何工作的
How does this C++ template class code work?
我正在尝试将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
"——这个函数实际上不会被调用。
- QSqlquery prepare()和bindvalue()不工作
- 导入库可以跨dll版本工作吗
- 以螺旋方式打印矩阵的程序.(工作不好)
- 对象指针在c++中是如何工作的
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- C++为线程工作动态地分割例程
- 为什么我的 std::ref 无法按预期工作?
- 布尔比较运算符是如何在C++中工作的
- SampleConsensusPrerejective(ext.RANSAC)是如何真正工作的
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- <<操作员在下面的行中工作
- 有人能解释一下为什么下界是这样工作的吗C++的
- ExtractIconEx:可以工作,但偶尔会崩溃
- C++中的memset函数工作不正常
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 链表c++插入,所有情况都已检查,但没有任何工作
- 当 int 方法工作正常时,void 方法有何不同,或者为什么我不能调用 void 方法?