enable_if 在 return 类型中没有 decltype 失败
enable_if fails without decltype in return type
我有 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; }
和returns正确的结果
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
为什么以及如何帮助解决这种情况?
默认(模板)参数不是签名的一部分,
应该是
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; }
};
那些不是重载;它们是同一函数模板的重新声明(和重新定义):
template<class, int, class> auto data();
默认模板参数不做不同的函数模板;推导的 return 类型也没有,但是将 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
我有 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; }
和returns正确的结果
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
为什么以及如何帮助解决这种情况?
默认(模板)参数不是签名的一部分,
应该是
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; }
};
那些不是重载;它们是同一函数模板的重新声明(和重新定义):
template<class, int, class> auto data();
默认模板参数不做不同的函数模板;推导的 return 类型也没有,但是将 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