Question

The following code compiles (and runs) just fine, even though I would expect it to produce a compile-time error:

#include <iostream>

using namespace std;

template <typename T>
struct is_int {
    static const bool value = false;
};

template<>
struct is_int<int> {
    static const bool value = true;
};

// General template definition with default second type parameter (void)
template <typename A, typename B = void>
struct Foo {
    static const int i = 42;
};

// Partially specialized template definition with possibly
// undefined second parameter
template<typename A>
struct Foo<A, typename enable_if<is_int<A>::value>::type > {
    static const int i = 56;
};


int main() {
    cout << Foo<bool>::i << endl; // Outputs '42'
    cout << Foo<int>::i << endl; // Outputs '56'
    return 0;
}

The enable_if template inside the partial specialization of struct Foo does only define the member type type if the first argument is the value true. See the reference page.

So, when the first line in the main function instantiates template Foo, what exactly does the compiler do? Clearly, when it tries to match the partial specialization, it would run into an error (because type is not defined).

Does it simply discard this choice in order to avoid an error?

Was it helpful?

Solution

What you are experiencing is the basic of template introspection and it is called SFINAE.

Simply put: when a template parameter substitution fails, it doesn't throw but simply "move on" and grab the next candidate that doesn't result in a deduction failure. This can be useful to do some compile-time analysis.

Boost's enable_if is base on SFINAE.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top