4

这是我有点奇怪的代码:

template <typename T&>
class A {  
public:  
  void b(typename std::enable_if<!std::is_pointer<T>::value, T>;::type o) {}  
  void b(typename std::enable_if<std::is_pointer<T>::value, T>;::type o) {}  
};  

template <typename T>  
void b(typename std::enable_if<!std::is_pointer<T>::value, T>::type o) {}  
template <typename T>  
void b(typename std::enable_if<std::is_pointer<T>::value, T>::type o) {}  

如果我ifdef退出方法b并调用b<int *>(pi) where piis int *,一切都会编译。

如果我ifdef退出函数b(类外)并调用A<int *> a; a.b(pi),我会收到以下错误:

error: no type named 'type' in 'std::__1::enable_if<false, int *>'

为什么不一致以及如何解决问题以便我可以使用 A 中的方法?

4

3 回答 3

9

问题是,SFINAE 仅在重载解析期间并且仅当函数本身是模板时才有效。在您的方法案例中,整个是一个模板,这意味着没有模板参数的替换(请记住:SFINAE ==“替换失败不是错误”)。

在实例化点,方法签名看起来像这样(不要介意对它们的调用):

void A<int*>::b(std::enable_if<false, int*>::type o) // error
void A<int*>::b(std::enable_if<true, int*>::type o)

为了解决这个问题,也制作方法模板:

template<class T>
class A{
public:
  template<class U>
  void b(U o, typename std::enable_if<!std::is_pointer<U>::value>::type* = 0){}
  // same for the other version
};

附带说明一下,推导模板参数是使用 SFINAE 的更好方法,因此您应该将自由函数修改为如下所示:

template<class T>
void b(T o, typename std::enable_if<!std::is_pointer<T>::value>::type* = 0){}
// same for the other version

在 C++11 中,您甚至可以使用 SFINAE 的模板参数:

template<class T, EnableIf<std::is_pointer<T>> = {}>
void b(T o);

使用从此处链接的博客条目中的别名:

namespace detail{ enum class enabler{}; }

template<class Cond, class T = detail::enabler>
using EnableIf = typename std::enable_if<C::value, T>::type;
于 2012-06-28T15:56:31.347 回答
4

有关解释,请参阅 Xeo 的答案。

解决方法:只需在方法中添加一个虚拟模板参数

#include <utility>
#include <type_traits>

template <typename T>
class A {  
public:
  template <typename U = T>
  void b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o);

  template <typename U = T>
  void b(typename std::enable_if<std::is_pointer<U>::value, U>::type o);
};

template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o) {}  

template <typename T>  
template <typename U>
void A<T>::b(typename std::enable_if<std::is_pointer<U>::value, U>::type o) {} 


int main() {
    A<int> a;
    a.b(0);
}

现场演示在这里

于 2012-06-28T16:15:31.793 回答
0

您没有正确使用 SFINAE,因为编译器无法推断出参数,enable_if<...>::type这可能就是它失败的原因。

独立函数的正确声明是:

template <typename T>  
typename std::enable_if<!std::is_pointer<T>::value, void>::type b(T o);

template <typename T>  
typename std::enable_if<std::is_pointer<T>::value, void>::type b(T o);

在这种特殊情况下,也可以使用普通函数重载:

template <typename T>  
void b(T);

template <typename T>  
void b(T*);
于 2012-06-28T15:58:58.347 回答