简体   繁体   English

enable_if 在返回类型中没有 decltype 失败

[英]enable_if fails without decltype in return type

I have 3 overloads of a function each guarded by enable_if我有 3 个 function 的重载,每个重载都由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; }
};

The above code fails to compile with error上面的代码编译失败,报错

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; }

Each of these functions can be distinguished from each other with the third template argument.这些函数中的每一个都可以通过第三个模板参数相互区分。 What is the reason behind SFINAE failure? SFINAE失败的原因是什么?

On the other hand the following works另一方面,以下工作

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; }

and returns correct results并返回正确的结果

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

Why and how decltype helps in this situation? decltype为什么以及如何在这种情况下提供帮助?

Default (template) argument is not part of signature,默认(模板)参数不是签名的一部分,

It should be它应该是

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; }
};

Those are not overloads;那些不是重载; they are redeclarations (and redefinitions) of the same function template:它们是相同 function 模板的重新声明(和重新定义):

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

Default template parameters do not make a different function template;默认模板参数不做不同的function模板; nor does a different deduced return type, however swapping auto for decltype(auto) does make a different function template.也没有不同的推导返回类型,但是将auto替换为decltype(auto)确实会生成不同的 function 模板。

If suitable, the best solution would be to use concepts , since a different template-constraint makes for a different function template:如果合适,最好的解决方案是使用概念,因为不同的模板约束会产生不同的 function 模板:

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; }

Otherwise, you could add more dummy template arguments :否则,您可以添加更多虚拟模板 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

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

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