How does this C ++ template code code work?

I am trying to port the Google test ( gtest ) to VxWorks 5.5. A serious drawback is that the Tornado 2.2 development environment uses the ancient GCC compiler version 2.96.

When analyzing the code, I found a piece of code in gtest.h , I do not understand! How does this class of C ++ templates work?

 // ImplicitlyConvertible<From, To>::value is a compile-time bool // constant that 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 }; 

When an object of this class is created, a boolean named value must contain the answer if the From template type is implicitly converted to the To template type. To get the answer, two private functions are used, MakeFrom() and Helper() . But these two functions are declared here, and I cannot find a definition for either of them. If nothing else, this implementation should not be bound.

I also do not understand the syntax of the following

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

Of course, this code compiles just fine (under Microsoft Visual C ++ 7.1 or later or GCC 3.4 or later), and the guys from Google know exactly what they are doing.

Please enlighten me! Without understanding this code, I'll lose my mind! :)

+4
source share
1 answer

This is a standard pattern programming trick.

Note that the comments say "checking helper size (x)": this emphasizes that the only thing the code does with Helper is sizeof(Helper(x)) for some x . The sizeof operator does not actually evaluate its argument (it does not need it, it only needs to find out how big it is, that it is possible to use only the information available at compile time), and therefore there is no linker error ( Helper never called).

The syntax that gives you problems means that Helper is a function that takes any number and type of parameters and returns a reference to char[2] . To write a signature for this type of function (a variational function ), you need to use an ellipsis ( ... ) as the specification for the last argument.

Variadic functions is a function inherited from C that should usually be avoided and that causes chaos when used with class types, but in this case it does not matter because, as mentioned earlier, Helper will not be called.

The class binds this all together, allowing you to use syntax

 ImplicitlyConvertible<From, To>::value 

To create a value , the code "fakes" a Helper call and passes it a From instance as an argument¹. It relies on compiler overload resolution to determine if an overload that takes To in this scenario will be called; if so, the return value of this overload is char , which has a guaranteed size of 1 , and value ends with true . Otherwise, the variable overload (which takes any type of argument) is selected, which returns char[2] . This has a size greater than 1 , so value ends with false .


¹ Note that here the “ sizeof doesn't actually evaluate the expression” trick is used again: how do you tell the compiler that the Helper argument is an From instance? You can use From() , but then From will have to have a default public constructor to compile the code. Therefore, you simply tell the compiler "I have a MakeFrom function that returns From " - the function will not actually be called.

+10
source

Source: https://habr.com/ru/post/1432029/


All Articles