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<...>::type
is, 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 is void
.
Let's look at your second version of the template. If sizeof(T) <= 1
, you provide a template specialization for test<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 was void
, this means objs1
is actually of type test<char, void>
. And we actually have a specialization for test<char, void>
, because sizeof(char) <= 1
is true
.
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 int
instead of void
. Then test<char> objs1;
is actually declaring an object of type test<char, int>
. We have a specialization defined for test<char, void>
... But we aren't trying to create a test<char, void>
, we're trying to create the separate type test<char, int>
. So the fact that the condition of the enable_if
is true
is neither here nor there and we get the default definition of test
.
The technique that is being used is SFINAE implemented via partial template specialization . In order to have multiple different types of test
s depending on the characteristics of T
we need to have the SFINAE expression in the template parameter list. Since class cannot be overloaded you build an "overload set" by creating a main default template and then partial specializations for all of the different cases. To do that the main template needs to have two parameters, T
and the type that enable_if
will resolve to. We default that second parameter to void
so that it does not need to be specified by the caller to get the main template.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.