MCVE:
#include <type_traits>
template<typename T>
bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
{
}
enum class Bar { a,b,c };
int main()
{
Bar bar{Bar::a};
func(bar, 1);
}
Run Code Online (Sandbox Code Playgroud)
我希望func(bar, 1);能够匹配我对funcg ++报告的定义:
sfi.cc: In function 'int main()':
sfi.cc:13:17: error: no matching function for call to 'func(Bar&, int)'
func(bar, 1);
^
sfi.cc:13:17: note: candidate is:
sfi.cc:4:10: note: template<class T> bool func(typename std::enable_if<std::is_e
num<_Tp>::value, T>::type&, int)
bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
^
sfi.cc:4:10: note: template argument deduction/substitution failed:
sfi.cc:13:17: note: couldn't deduce template parameter 'T'
func(bar, 1);
^
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用,我该如何解决?
背景:这是尝试解决此问题的方法
Yak*_*ont 10
template<typename T>
bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
Run Code Online (Sandbox Code Playgroud)
T以上在非演绎的上下文中使用.这意味着它不会扣除T,因为它(在一般情况下)需要逆转任意的图灵完全转换,这是不可能的.
什么func都有的是,第一个参数是一个enum class Bar,第二个是int.从这个你期望它推断T.
当设置T到enum class Bar不解决这个问题,C++不猜.它模式匹配.
假设我们有:
template<class T>
struct blah { using type=int; };
template<>
struct blah<int> { using type=double; };
Run Code Online (Sandbox Code Playgroud)
然后
template<class T>
bool func( typename blah<T>::type );
Run Code Online (Sandbox Code Playgroud)
如果有人经过一int到func,什么类型应该推导出T?这是一个玩具示例:foo<T>::type可以执行图灵完备算法以映射T到相关类型.在一般情况下,不可能反转或甚至确定逆是否是模糊的.因此,即使在简单的情况下,C++也不会尝试,因为简单和复杂之间的边缘很快就会模糊.
要解决您的问题:
template<class T,class=typename std::enable_if< std::is_enum<T>::value >::type>
bool func( T &t, int x ) {
}
Run Code Online (Sandbox Code Playgroud)
现在T用于推断的上下文中.SFINAE仍然出现,但不会阻止模板类型扣除.
或者你可以等待C++ 1z概念,它自动化上述结构(基本上).
查看链接的问题,解决问题的简便方法是使用标记调度.
template<typename T>
bool func(T &t, int x)
{
// do stuff...
}
Run Code Online (Sandbox Code Playgroud)
但是我希望有三个不同的功能体:
我们有3个案例:
T是一个枚举
T是unsigned char
其他一切
所以,派遣:
namespace details {
template<class T>
bool func( T& t, int x, std::true_type /* is_enum */, std::false_type ) {
}
template<class T>
bool func( T& t, int x, std::false_type, std::true_type /* unsigned char */ ) {
}
template<class T>
bool func( T& t, int x, std::false_type, std::false_type ) {
// neither
}
}
template<class T>
bool func( T& t, int x ) {
return details::func( t, x, std::is_enum<T>{}, std::is_same<unsigned char, T>{} );
}
Run Code Online (Sandbox Code Playgroud)
现在,正常的过载规则用于在3个函数之间进行选择.如果你不小心有一种既enum和unsigned char(不可能的),你会得到一个编译时错误.
您T在非推导的上下文中使用模板参数.
来自§14.8.2.5/ 5 [temp.deduct.type]
未推导的上下文是:
- 使用qualified-id 指定的类型的嵌套名称说明符. - ......
要解决此问题,请移至enable_if虚拟模板参数
template<typename T,
typename = typename std::enable_if< std::is_enum<T>::value, T >::type>
bool func( T &t, int x )
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
看看你链接的问题,你试图func根据第一个参数是否是一个来定义两个定义enum.在这种情况下,上述解决方案将无法工作,因为默认模板参数不是函数模板签名的一部分,并且最终会出现多个定义错误.
有两种不同的方法可以解决这个问题,使用虚拟模板参数
template<typename T,
typename std::enable_if< std::is_enum<T>::value, int >::type* = nullptr>
bool func( T &t, int x )
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
或使用enable_if返回类型中的表达式
template<typename T>
typename std::enable_if< std::is_enum<T>::value, bool >::type
func( T &t, int x )
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
enable_if您看到的错误与自动类型推导比和有关is_enum。
以下作品。
#include <iostream>
#include <type_traits>
template<typename T>
bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
{
return true;
}
enum class Bar { a,b,c };
int main()
{
Bar bar{Bar::a};
std::cout << func<decltype(bar)>(bar, 1) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
更新
正如OP已经发现的,decltype可以通过使用包装函数来避免使用。
#include <iostream>
#include <type_traits>
template <typename T>
bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
{
return true;
}
template <typename T>
bool func2( T &t, int x )
{
return func<T>(t,x);
}
enum class Bar { a,b,c };
int main()
{
Bar bar{Bar::a};
std::cout << func2(bar, 1) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)