nikitablack
nikitablack

Reputation: 4663

Need help to understand the purpose of a following class

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:

  1. How it can work if functions have a declaration only but no definition?
  2. What the TestT<T>::template test<T>(0) is? It looks like a function call.
  3. What is this ::template means?
  4. What's purpose of class above?
  5. How is used principle called?
  6. int C::* is a pointer to a int member, right?

Upvotes: 2

Views: 57

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254751

That's too many questions for a single question, but nevertheless:

  1. 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.

  2. Yes, that's a function call. If the class and function weren't templates, it would look like TestT::test(0).

  3. 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?.

  4. 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.

  5. 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.

  6. 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

danielschemmel
danielschemmel

Reputation: 11126

  1. It does not actually call the functions, it just looks at what the sizeof of the return type would be.
  2. It is a function call. See below.
  3. The template is necessary because of the dependent type problem.
  4. It tests if there can be a pointer to a data member of the type parameter. This is true for class types only (e.g. for 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.
  5. SFINAE, which stands for "Substitution Failure Is Not An Error". The reason for this name becomes obvious once you realize that the substitution of 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).
  6. Yes, it is a pointer that points to an int inside of an object of type C.

Upvotes: 3

Related Questions