enable_if with is_enum不工作 [英] enable_if with is_enum does not work

查看:124
本文介绍了enable_if with is_enum不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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> 
bool func(typename std :: enable_if< std :: is_enum< T> :: value,T> :: type& t,int x)
pre>

T 在上面的非推导上下文中使用。这意味着它不会扣除 T ,因为它(在一般情况下)需要反转任意图灵完成转换,这是不可能的。



func 的第一个参数是枚举类Bar 第二个是 int

在设置 T 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 of func 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 the T, 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 a enum class Bar, and the second is an int. From this you expect it to deduce T.

While setting T to enum 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 to func, what type should be deduced for T? This is a toy example: foo<T>::type can execute a Turing-complete algorithm to map T 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 and unsigned char (impossible), you get a compile-time error.

这篇关于enable_if with is_enum不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆