带有is_enum的enable_if不起作用

M.M*_*M.M 4 c++ sfinae c++11

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.

当设置Tenum 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)

如果有人经过一intfunc,什么类型应该推导出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个函数之间进行选择.如果你不小心有一种既enumunsigned char(不可能的),你会得到一个编译时错误.


Pra*_*ian 5

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)


R S*_*ahu 2

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)