I'm currently studying enable_if and I have this code:
//template<typename T, typename = int/double/float/...> //not working properly
template<typename T, typename = void> //works fine
struct test{
void func(){
cout << "default" << endl;
}
};
template<typename T>
struct test<T, typename std::enable_if<(sizeof(T) <= 1)>::type>{
void func(){
cout << "called" << endl;
}
};
int main() {
test<char> objs1;
objs1.func(); //called
test<int> objs2;
objs2.func(); //default
}
I don't know the reason why I have to set the second parameter's default value as void. If I set it to other values like int or float or double, both objs1.func(); and objs2.func(); will print default. What is the reason?
So,
std::enable_if<...>::typeis, in fact, a type. Because you didn't specify what the type should be, you just specified the condition for which it exists at all, the default isvoid.Let's look at your second version of the template. If
sizeof(T) <= 1, you provide a template specialization fortest<T, void>. Otherwise, the substitution fails and you provide nothing.Now let's consider what happens when you just write
test<char> objs1;. In your original version, because the default value for the unnamed second template parameter wasvoid, this meansobjs1is actually of typetest<char, void>. And we actually have a specialization fortest<char, void>, becausesizeof(char) <= 1istrue.However, if you change the default value of the unnamed second template parameter, we get a very different situation. Say you make the default value
intinstead ofvoid. Thentest<char> objs1;is actually declaring an object of typetest<char, int>. We have a specialization defined fortest<char, void>... But we aren't trying to create atest<char, void>, we're trying to create the separate typetest<char, int>. So the fact that the condition of theenable_ifistrueis neither here nor there and we get the default definition oftest.