1
template<class T>
struct is_class_or_union
{
    struct twochar { char _[2]; };
    template <class U>
    static char is_class_or_union_tester(void(U::*)(void));
    template <class U>
    static twochar is_class_or_union_tester(...);
    static const bool value = sizeof(is_class_or_union_tester<T>(0)) == sizeof(char);
};

The above code is from meta_utils.hpp from boost library.

  1. is_class_or_union_tester seems to be a static function returning char and taking pointer to a member function (that returns void and accepts nothing). There is no function body and it does not seem to be defined anywhere else. I do not understand how it works and above all, I do not understand the purpose of the function.
  2. I do not understand the concept of the following code: static const bool value = sizeof(is_class_or_union_tester<T>(0)) == sizeof(char); What is the sizeof operator applied to? What are they trying to find here ?
Yuushi
  • 25,132
  • 7
  • 63
  • 81
  • possible duplicate of [C++ SFINAE examples?](http://stackoverflow.com/questions/982808/c-sfinae-examples) – awesoon Aug 30 '13 at 04:47
  • @peter Thank you for the explanation. It certainly helped. I wonder there was no linker error (for the function definition) because the function was never called ? – Harish Ramanathan Aug 30 '13 at 05:24
  • There was no linker error because no code was actually created. `sizeof` doesn't actually execute the expressions that it is passed, but rather figures out the type of the result, and then calculates the size of that. – Marshall Clow Aug 30 '13 at 05:33
  • And yes, neither implementation of `is_class_or_union_tester` is ever called. – Marshall Clow Aug 30 '13 at 05:34

1 Answers1

3

The technique being employed here is SFINAE (substitution failure is not an error) which is a technique used by the compiler to select a match among possible candidate templates and specifically where an invalid substitution of template parameters is not in itself an error during that matching process. In this case the compiler is attempting to find a match for:

is_class_or_union_tester<T>(0)

It can select between

template <class U>
static char is_class_or_union_tester(void(U::*)(void));

or

template <class U>
static twochar is_class_or_union_tester(...);

If T is a class it will select the first function template because a class can have a member function. If T is a union it will select the second. Recall that sizeof does not execute the functions and will act only on the return types in the template declarations. You'll see that the return types are different and that makes the comparison against sizeof(char) return the correct value.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Peter R
  • 2,865
  • 18
  • 19
  • Makes me wonder, if the language allows and people use this kind of mechanism, perhaps an explicit way to do that should be designed. This seems very, very hacky. – szpanczyk Mar 25 '17 at 13:52