Reputation: 4663
The friend of mine send me an interesting task:
template<typename T>
class TestT
{
public:
typedef char ONE;
typedef struct { char a[2]; } TWO;
template<typename C>
static ONE test(int C::*);
template<typename C>
static TWO test(...);
public:
enum{ Yes = sizeof(TestT<T>::template test<T>(0)) == 1 };
enum{ No = !Yes };
};
I can't compile this code with VS2013. With GCC 4.9.0 it compiles. But I can't understand what it does.
The points of interest for me:
TestT<T>::template test<T>(0)
is? It looks like a function call.::template
means?int C::*
is a pointer to a int
member, right?Upvotes: 2
Views: 57
Reputation: 254751
That's too many questions for a single question, but nevertheless:
sizeof
doesn't evaluate its operand, it only determines the type. That doesn't require definitions for any functions called by the operand - the type is determined from the declaration.
Yes, that's a function call. If the class and function weren't templates, it would look like TestT::test(0)
.
template
is needed because the meaning of the name test
depends on the class template parameter(s), as described in Where and why do I have to put the "template" and "typename" keywords?.
It defines a constant Yes
which is one if T
is a class type and zero otherwise. Also a constant No
with the logically inverted value.
It looks like it's intended for use in SFINAE, to allow templates to be partially specialised for class and non-class types. Since C++11, we can use standard traits like std::is_class
for this purpose.
Yes, if C
is a class type. Otherwise, it's a type error, so the overload taking that type is ignored, leaving just the second overload. Thus, the return type of test
is ONE
(with size one) if C
is a class type, and TWO
(with size two) otherwise; so the test for sizeof(...) == 1
distinguishes between class and non-class types.
Upvotes: 1
Reputation: 11126
sizeof
of the return type would be.template
is necessary because of the dependent type problem.std::string
but not for int
). You can find code like this for example here which includes something very similar to your example - under the name of is_class
.C
for int
will fail and thus simply cause one of the function overloads to not exist (instead of causing a compiler error and aborting compilation).int
inside of an object of type C
.Upvotes: 3