这是我有点奇怪的代码:
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
)pi
为int *
,那么一切都会编译。
如果我ifdef
输出函数b
(课外)并调用A<int *> a; a.b(pi)
,我会收到以下错误:
error: no type named 'type' in 'std::__1::enable_if<false, int *>'
为什么不一致以及如何解决问题以便我可以使用A中的方法?
答案 0 :(得分: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);
利用here链接的博客条目中的别名:
namespace detail{ enum class enabler{}; }
template<class Cond, class T = detail::enabler>
using EnableIf = typename std::enable_if<C::value, T>::type;
答案 1 :(得分: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);
}
答案 2 :(得分: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*);