【问题标题】:Member function template selection and SFINAE成员函数模板选择和SFINAE
【发布时间】:2016-09-15 12:06:12
【问题描述】:

我一直试图了解 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

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

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

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

错误 C2535: 'void Curious::test2(void)': 成员函数已定义或声明

Here 文档说:

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

看来是这样。但是,我看不出与前两个函数有太大区别,它们也有默认的模板参数。因此,我们有一个默认类型(test2 - 不工作)与默认值(test1 - 工作)。有什么规定吗?

如果是test3:

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

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

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

我对 C++ 如何处理这些模板感到很困惑。有人能这么好心把这些事情弄清楚吗?

【问题讨论】:

标签: c++ templates sfinae enable-if


【解决方案1】:
  • 删除默认值后,对于 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();
    

    签名明显不同。

  • 对于测试2:

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

    明显相同的签名。

  • 对于 test3,SFINAE 不适用,因为您有硬错误,因为 R 已在类中修复,而您的 enable_if 不依赖于函数的模板参数。

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

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

    但是

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

    另外std::enable_if&lt;!std::is_const&lt;R&gt;::value, T&gt;::type依赖于模板参数T所以没问题。

  • 对于test5,第二个模板参数依赖于第一个模板参数T,所以也可以。

【讨论】:

  • 谢谢,我刚刚在我的原始帖子中添加了两个示例
  • 为 test4/test5 添加了解释:enable_if 在这两种情况下都依赖于 T
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多