成员函数模板选择和SFINAE

men*_*oom 7 c++ templates sfinae enable-if

我一直在努力理解C++选择模板的方式.即,请考虑以下代码示例:

template <typename R>
class Curious
{
public:
    template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type = 33>
    void test1() {}

    template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 33>
    void test1() {}

    template <typename T, typename = typename std::enable_if<std::is_const<T>::value>::type>
    void test2() {}

    template <typename T, typename = typename std::enable_if<!std::is_const<T>::value>::type>
    void test2() {}

    template <typename std::enable_if<std::is_const<R>::value>::type * = nullptr>
    void test3() {}

    template <typename std::enable_if<!std::is_const<R>::value>::type * = nullptr>
    void test3() {}

    // works
    template <typename T = void>
    typename std::enable_if<std::is_const<R>::value, T>::type test4() {}

    template <typename T = void>
    typename std::enable_if<!std::is_const<R>::value, T>::type test4() {}

    // also works
    template <typename T = void, typename std::enable_if<std::is_const<R>::value, T>::type * = nullptr>
    void test5() {}

    template <typename T = void, typename std::enable_if<!std::is_const<R>::value, T>::type * = nullptr>
    void test5() {}
}; // Curious
Run Code Online (Sandbox Code Playgroud)

前两个函数(test1)工作正常(为什么?):

Curious<int> curious;
curious.test1<int>();
curious.test1<const int>();
Run Code Online (Sandbox Code Playgroud)

而其余的则导致编译错误.关于函数test2,编译器声称我正在尝试创建一个副本:

error C2535: 'void Curious::test2(void)': member function already defined or declared

这里的文档说:

一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板.这是非法的,因为默认模板参数不是函数模板签名的一部分,并且声明具有相同签名的两个不同函数模板是非法的.

所以情况似乎如此.但是,我没有看到与前两个函数有太大区别,前两个函数也有默认的模板参数.因此,我们对默认值(test1 - works)有一个默认类型(test2 - 不起作用).关于它有什么规则吗?

在test3的情况下:

error C2039: 'type': is not a member of 'std::enable_if'
与第一种情况一样,这次成员函数模板具有默认的非类型参数,但它取决于类模板参数.现在SFINAE没有跳过错误的(也不知道为什么).

在第四种情况下,SFINAE通过返回类型解析模板.但这些test4函数是否具有相同的签名?因为它们仅在返回类型上有所不同.

据我所知,在第五种情况下,添加额外参数使test5签名依赖于函数模板参数,因此SFINAE启动并且解析工作.

我对C++如何处理这些模板感到很困惑.有人可以这么清楚这些事吗?

Jar*_*d42 9

  • 删除默认值后,对于test1,您有:

    template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type>
    void test1();
    
    template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type>
    void test1();
    
    Run Code Online (Sandbox Code Playgroud)

    其中有明显不同的签名.

  • 对于test2:

    template <typename T, typename> void test2();
    
    template <typename T, typename> void test2();
    
    Run Code Online (Sandbox Code Playgroud)

    哪些是明显相同的签名.

  • 对于test3,SFINAE不适用,因为您R在类中修复了硬错误,并且您enable_if不依赖于函数的模板参数.

  • 对于test4,模板函数的签名有一个例外,因为重载可能仅因返回类型而异

    int foo();
    char foo(); // Illegal.
    
    Run Code Online (Sandbox Code Playgroud)

    template <typename T> int foo();
    template <typename T> char foo(); // legal, even it is not trivial to call
    
    Run Code Online (Sandbox Code Playgroud)

    另外,std::enable_if<!std::is_const<R>::value, T>::type取决于模板参数,T所以没关系.

  • 对于test5,第二个模板参数取决于第一个模板参数T,所以也可以.