10

While reading this question , I came across @Johannes's answer.

template<typename> struct void_ { typedef void type; };

template<typename T, typename = void>  // Line 1
struct is_class { static bool const value = false; };

template<typename T>
struct is_class<T, typename void_<int T::*>::type> { // Line 2
  static bool const value = true; 
};

This construct finds if the given type is a class or not. What puzzles me is the new kind of syntax for writing this small meta program. Can anyone explain in detail:

  1. Why we need Line 1 ?
  2. What is the meaning of syntax <int T::*> as template parameter in Line 2 ?
Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336

2 Answers2

10

Line 1: Choosing the partial specialization below if the test succeeds.

Line 2: int T::* is only valid if T is a class type, as it denotes a member pointer.

As such, if it is valid, void_<T>::type yields void, having this partial specialization chosen for the instantiation with a value of true. If T is not of class type, then this partial specialization is out of the picture thanks to SFINAE and it defaults back to the general template with a value of false.

Everytime you see a T::SOMETHING, if SOMETHING isn't present, be it a type, a data member or a simple pointer definition, you got SFINAE going.

Xeo
  • 129,499
  • 52
  • 291
  • 397
  • 2
    Why is going through `struct is_class::type>` (instead of the simpler `struct is_class`) needed? (The second compile but doesn't give the wanted result) – AProgrammer Jul 01 '11 at 05:58
  • @AProgrammer: How does the second compile if you don't know the class type? How would you choose the default, which in this case is `typename = void`? – Xeo Jul 01 '11 at 06:06
  • 2
    Why `void_::type` and default parameter in the first version of `is_class` (i.e. `typename = void`) needs to be same ? – iammilind Jul 01 '11 at 14:13
  • 1
    @iammilind: If `int T::*` is valid, the partial specialization will read `is_class` and will be chosen thanks to the `void` default. That wouldn't happen if both were different. – Xeo Jul 02 '11 at 05:33
1

1. line 1 is used for something which is not a class, like int, long and so on ...

for example:

class foo {};

if (is_class<foo>::value) // is a class
    line_2 called
else  // if not
    line 1 called

because of there is a partial specialization so line 1 is what you have to have, otherwise you will get an error if you pass a type which is not a class (such as char *, long, int ...)

2: the key of int T::* is "::*", it is a standard operator in c++

means a pointer points to a member of a class, can be both a function or a data field, and in this case it means anyone who has a member or can work with a member pointer, this is only works for classes, structs, or unions in c++, so the result of that, you will know the parameter is or not a class.

btw, google some keywords like: c++ template, partial specialization, and type traits, or boost type traits

hope this is useful for you :)

Community
  • 1
  • 1
runo
  • 46
  • 1