enable_if with is_enum不工作 [英] enable_if with is_enum does not work
问题描述
MCVE:
#include< type_traits>
template< typename T>
bool func(typename std :: enable_if< std :: is_enum< T> :: value,T> :: type& t,int x)
{
} $ b b
枚举类Bar {a,b,c};
int main()
{
Bar bar {Bar :: a};
func(bar,1);
}
我希望 func(bar,1) / code>以匹配我对
func
的定义,但g ++报告:
sfi.cc:在函数'int main()':
sfi.cc:13:17:error:没有匹配函数调用'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:模板参数扣除/替换失败:
sfi.cc:13:17:注意:无法推导出模板参数'T'
func(bar,1);
^
为什么这不工作,如何解决? >
背景:这是一个尝试解决方案此问题
template< typename T>
pre>
bool func(typename std :: enable_if< std :: is_enum< T> :: value,T> :: type& t,int x)
T
在上面的非推导上下文中使用。这意味着它不会扣除T
,因为它(在一般情况下)需要反转任意图灵完成转换,这是不可能的。
func
的第一个参数是枚举类Bar
第二个是int
。
在设置
T $ c时,您希望它推导出
T
$ c>到枚举类Bar
确实解决了问题,C ++没有猜到。
假设我们有:
template< class T>
struct blah {using type = int; };
模板<>
struct blah< int> {using type = double; };
然后
template< class T>
bool func(typename blah< T> :: type);
如果有人将
int
传递给func
,应该为T
推导什么类型?这是一个玩具示例:foo< T> :: type
可以执行Turing完成算法,将T
映射到所讨论的类型。反之亦然,或者甚至确定反相是否是不明确的,在一般情况下是不可能的。所以C ++甚至不尝试,即使在简单的情况下,因为简单和复杂之间的边缘很快模糊。
要解决你的问题:
模板< class T,class = typename std :: enable_if< std :: is_enum< T> :: value> :: type>
bool func(T& t,int x){
}
现在
T
用于推导的上下文中。 SFINAE仍然会发生,但不会阻止模板类型的扣除。
或者你可以等待C ++ 1z的概念,自动化上述结构(基本上)。
查看链接的问题,解决问题的简单方法是使用标签分派。
模板
bool func(T& t,int x)
{
// do stuff ...
}
但我想有三个不同的函数体:
我们有3个例子:
T是枚举b $ b T无符号char
其他
so,dispatch:命名空间详细信息{
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){
//没有
}
}
模板< class T> ;
bool func(T& t,int x){
return details :: func(t,x,std :: is_enum< T> {},std :: is_same< unsigned char,T& });
}
现在正常的重载规则用于在3个函数之间选择。如果你有某种类型的
enum
和unsigned char
(不可能),你会得到一个编译时错误。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); }
I expect
func(bar, 1);
to match my definition offunc
however g++ reports: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); ^
Why isn't this working and how do I fix it?
Background: This was an attempted solution to this problem
解决方案template<typename T> bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
T
is used above in a non-deduced context. This means it won't deduct theT
, as it (in the general case) requires reversing an arbitrary turing-complete transformation, which is impossible.What
func
has is that the first argument is aenum class Bar
, and the second is anint
. From this you expect it to deduceT
.While setting
T
toenum class Bar
does solve the problem, C++ doesn't guess. It pattern matches.Suppose we had:
template<class T> struct blah { using type=int; }; template<> struct blah<int> { using type=double; };
then
template<class T> bool func( typename blah<T>::type );
If someone passes a
int
tofunc
, what type should be deduced forT
? This is a toy example:foo<T>::type
can execute a Turing-complete algorithm to mapT
to the type in question. Inverting that or even determining if the inverse is ambiguous, is not possible in the general case. So C++ doesn't even try, even in the simple cases, as the edge between simple and complex gets fuzzy quickly.To fix your problem:
template<class T,class=typename std::enable_if< std::is_enum<T>::value >::type> bool func( T &t, int x ) { }
now
T
is used in a deduced context. The SFINAE still occurs, but doesn't block template type deduction.Or you can wait for C++1z concepts, which automate the above construct (basically).
Looking at the linked question, the easy way to solve your problem is with tag dispatching.
template bool func(T &t, int x) { // do stuff... }
However I would like to have three different function bodies:
We have 3 cases: T being an enum T being unsigned char Everything else so, dispatch:
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>{} ); }
now normal overload rules are used to pick between the 3 functions. If you somehow have a type that is both
enum
andunsigned char
(impossible), you get a compile-time error.这篇关于enable_if with is_enum不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!