我目前正在学习enable_if
。但是我有这样的代码:
//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
}
我不知道为什么要把第二个参数的默认值设置为void
,如果我把它设置为其他值,如int
或float
或double
,objs1.func();
和objs2.func();
都将打印默认值,原因是什么?
2条答案
按热度按时间o3imoua41#
所以,
std::enable_if<...>::type
实际上是一个类型,因为你没有指定类型应该是什么,你只是指定了它存在的条件,default就是void
。让我们看一下模板的第二个版本,如果是
sizeof(T) <= 1
,则为test<T, void>
提供模板专门化,否则替换失败,不提供任何内容。现在让我们考虑一下当你只写
test<char> objs1;
时会发生什么,在你的原始版本中,因为未命名的第二个模板参数的默认值是void
,这意味着objs1
实际上是test<char, void>
类型,而且我们实际上有一个test<char, void>
的特殊化,因为sizeof(char) <= 1
是true
。但是,如果更改未命名的第二个模板参数的默认值,我们会得到非常不同的情况,假设您将默认值设置为
int
而不是void
,那么test<char> objs1;
实际上声明了test<char, int>
类型的对象,我们为test<char, void>
定义了一个专门化......但我们并不试图创建一个test<char, void>
,我们试图创建一个独立的类型,所以enable_if
的条件是true
的事实并不存在,我们得到了默认的定义。imzjd6km2#
所使用的技术是通过partial template specialization实现的SFINAE。为了根据
T
的特性拥有多种不同类型的test
,我们需要在模板参数列表中拥有SFINAE表达式。由于类不能被重载,因此构建了“重载集”通过创建一个主默认模板,然后为所有不同的情况进行部分专门化。要做到这一点,主模板需要有两个参数,T
和enable_if
将解析到的类型。我们将第二个参数默认为void
,这样调用者就不需要指定它来获取主模板。