简体   繁体   English

成员函数模板选择和SFINAE

[英]Member function template selection and SFINAE

I've been trying to understand the way C++ selects templates. 我一直在努力理解C ++选择模板的方式。 Namely, consider the following code sample: 即,请考虑以下代码示例:

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

The first two functions (test1) work fine ( why? ): 前两个函数(test1)工作正常( 为什么? ):

Curious<int> curious;
curious.test1<int>();
curious.test1<const int>();

While the rest of them cause compilation errors. 而其余的则导致编译错误。 Regarding the function test2 the compiler claims I'm trying to create a duplicate: 关于函数test2,编译器声称我正在尝试创建一个副本:

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

Here the documentation says: 这里的文档说:

A common mistake is to declare two function templates that differ only in their default template arguments. 一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板。 This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal. 这是非法的,因为默认模板参数不是函数模板签名的一部分,并且声明具有相同签名的两个不同函数模板是非法的。

So it seems to be the case. 所以情况似乎如此。 However, I don't see that much difference from the first two functions, which also have the default template argument. 但是,我没有看到与前两个函数有太大区别,前两个函数也有默认的模板参数。 Thus we have a default type (test2 - doesn't work) against a default value (test1 - works). 因此,我们对默认值(test1 - works)有一个默认类型(test2 - 不起作用)。 Is there any rule about it? 关于它有什么规则吗?

In case of test3: 在test3的情况下:

error C2039: 'type': is not a member of 'std::enable_if'
Like in the first case this time the member function template has a default non-type parameter, but it depends on the class template parameter. 与第一种情况一样,这次成员函数模板具有默认的非类型参数,但它取决于类模板参数。 Now SFINAE doesn't skip the wrong one (also not sure why). 现在SFINAE没有跳过错误的(也不知道为什么)。

In the fourth case SFINAE resolves the template by the return type. 在第四种情况下,SFINAE通过返回类型解析模板。 But don't these test4 functions have identical signature? 但这些test4函数是否具有相同的签名? As they differ only in the return type. 因为它们仅在返回类型上有所不同。

As far as I understand, in the fifth case adding extra parameter makes test5 signature dependent on the function template parameter, therefore SFINAE kicks in and resolution works. 据我所知,在第五种情况下,添加额外参数使test5签名依赖于函数模板参数,因此SFINAE启动并且解析工作。

I'm quite confused about how C++ deals with these templates. 我对C ++如何处理这些模板感到很困惑。 Could somebody be so kind to clear these things up? 有人可以这么清楚这些事吗?

  • With default value removed, for test1, you have: 删除默认值后,对于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(); 

    Which have clearly different signatures. 其中有明显不同的签名。

  • For test2: 对于test2:

     template <typename T, typename> void test2(); template <typename T, typename> void test2(); 

    Which are clearly identical signatures. 哪些是明显相同的签名。

  • For test3, SFINAE doesn't apply as you have hard error as R is fixed in the class and your enable_if doesn't depend of template parameter of the function. 对于test3,SFINAE不适用,因为您有硬错误,因为类中的R已修复且您的enable_if不依赖于函数的模板参数。

  • For test4, there is an exception about signature for template function as overload may differ only by return type so 对于test4,模板函数的签名有一个例外,因为重载可能仅因返回类型而异

     int foo(); char foo(); // Illegal. 

    but

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

    In addition, std::enable_if<!std::is_const<R>::value, T>::type depends on template parameter T so it is ok. 另外, std::enable_if<!std::is_const<R>::value, T>::type依赖于模板参数T所以没关系。

  • For test5, second template parameter depends on first template parameter T , so it is ok too. 对于test5,第二个模板参数取决于第一个模板参数T ,所以也可以。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM