c++ 为什么在类模板中使用enable_if时必须将第二个参数的默认类型设置为void?

xwbd5t1u  于 2023-01-18  发布在  其他
关注(0)|答案(2)|浏览(201)

我目前正在学习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,如果我把它设置为其他值,如intfloatdoubleobjs1.func();objs2.func();都将打印默认值,原因是什么?

o3imoua4

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) <= 1true
但是,如果更改未命名的第二个模板参数的默认值,我们会得到非常不同的情况,假设您将默认值设置为int而不是void,那么test<char> objs1;实际上声明了test<char, int>类型的对象,我们为test<char, void>定义了一个专门化......但我们并不试图创建一个test<char, void>,我们试图创建一个独立的类型,所以enable_if的条件是true的事实并不存在,我们得到了默认的定义。

imzjd6km

imzjd6km2#

所使用的技术是通过partial template specialization实现的SFINAE。为了根据T的特性拥有多种不同类型的test,我们需要在模板参数列表中拥有SFINAE表达式。由于类不能被重载,因此构建了“重载集”通过创建一个主默认模板,然后为所有不同的情况进行部分专门化。要做到这一点,主模板需要有两个参数,Tenable_if将解析到的类型。我们将第二个参数默认为void,这样调用者就不需要指定它来获取主模板。

相关问题