【问题标题】:enable_if fails without decltype in return typeenable_if 在返回类型中没有 decltype 失败
【发布时间】:2021-04-01 03:49:01
【问题描述】:

我有 3 个函数重载,每个函数都由 enable_if 保护

struct thing{
    typedef int data_type;
    
    template <typename T, int N = 0, typename = typename std::enable_if<N == 0 &&  std::is_same<T, data_type>::value>::type>
    data_type data() { return 1; }
    template <typename T, int N = 0, typename = typename std::enable_if<N == 0 && !std::is_same<T, data_type>::value>::type>
    auto data() { return 0; }
    template <typename T, int N, typename = typename std::enable_if<N != 0>::type>
    auto data() { return -1; }
};

以上代码编译失败,报错

test.cpp:12:10: error: ‘template<class T, int N, class> auto thing::data()’ cannot be overloaded with ‘template<class T, int N, class> auto thing::data()’
   12 |     auto data() { return -1; }
      |          ^~~~
test.cpp:10:10: note: previous declaration ‘template<class T, int N, class> auto thing::data()’
   10 |     auto data() { return 0; }

这些函数中的每一个都可以通过第三个模板参数相互区分。 SFINAE 失败的原因是什么?

另一方面,以下工作

template <typename T, int N = 0, typename = typename std::enable_if<N == 0 && !std::is_same<T, data_type>::value>::type>
auto data() { return 0; }
template <typename T, int N, typename = typename std::enable_if<N != 0>::type>
decltype(auto) data() { return -1; }

并返回正确的结果

thing t;
std::cout << "t.data<int>(): "       << t.data<int>() << std::endl;       //  1
std::cout << "t.data<double>(): "    << t.data<double>() << std::endl;    //  0
std::cout << "t.data<int, 1>(): "    << t.data<int, 1>() << std::endl;    // -1
std::cout << "t.data<double, 1>(): " << t.data<double, 1>() << std::endl; // -1

decltype 在这种情况下为何以及如何提供帮助?

【问题讨论】:

标签: c++ sfinae enable-if


【解决方案1】:

默认(模板)参数不是签名的一部分,

应该是

struct thing{
    typedef int data_type;
    
    template <typename T, int N = 0, typename std::enable_if<N == 0 &&  std::is_same<T, data_type>::value, int>::type = 0>
    data_type data() { return 1; }
    template <typename T, int N = 0, typename std::enable_if<N == 0 && !std::is_same<T, data_type>::value, int>::type = 0>
    auto data() { return 0; }
    template <typename T, int N, typename std::enable_if<N != 0, int>::type = 0>
    auto data() { return -1; }
};

【讨论】:

    【解决方案2】:

    那些不是重载;它们是同一函数模板的重新声明(和重新定义):

    template<class, int, class> auto data();
    

    默认模板参数不做不同的功能模板;也没有不同的推导返回类型,但是将 auto 交换为 decltype(auto) 确实会生成不同的函数模板。

    如果合适,最好的解决方案是to use concepts,因为不同的模板约束会产生不同的函数模板:

    template <typename T, int N = 0>
    data_type data() requires (N == 0 &&  std::is_same_v<T, data_type>) { return 1; }
    template <typename T, int N = 0>
    auto data() requires (N == 0 && !std::is_same_v<T, data_type>) { return 0; }
    template <typename T, int N>
    auto data() requires (N != 0) { return -1; }
    

    否则你可以add more dummy template arguments:

    template <typename T, int N = 0, typename = typename std::enable_if<N == 0 && !std::is_same<T, data_type>::value>::type>
    auto data() { return 0; }
    template <typename T, int N, int = 0, typename = typename std::enable_if<N != 0>::type>
    auto data() { return -1; } // ^^^^^^ add dummy template parameter
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-18
      • 1970-01-01
      • 2017-10-08
      相关资源
      最近更新 更多