我有一个 SFINAE问题:
在下面的代码中,我希望 C++ 编译器选择专用仿函数并打印“special”,但它打印的是“general”。
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
如何修复它以便自动使用专用结构?请注意,我不想直接将 Functor
结构专门化为 Foo
,但我想将其专门化为具有 Vec
类型的所有类型.
附言:我使用的是 g++ 4.4.4
最佳答案
很抱歉在最后的回答中误导了你,我想了想这样会更简单。所以我会尝试在这里提供一个完整的解决方案。解决此类问题的一般方法是编写一个 traits 辅助模板,并将其与 enable_if
(C++11、boost 或手动实现)一起使用来决定类特化:
特质
一个简单的方法,不一定是最好的,但写起来很简单:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
方法很简单,提供两个模板函数,返回不同大小的类型。其中一个采用嵌套的 Vec
类型,另一个采用省略号。对于所有具有嵌套 Vec
的类型,第一个重载是更好的匹配(省略号是任何类型的最差匹配)。对于那些没有嵌套 Vec
的类型,SFINAE 将丢弃该重载,剩下的唯一选项将是省略号。所以现在我们有一个特征来询问是否有任何类型具有嵌套的 Vec
类型。
启用如果
你可以从任何库中使用这个,或者你可以自己动手,这很简单:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
当第一个参数为 false
时,基本模板是唯一的选项,并且没有嵌套的 type
,如果条件为 true
,然后 enable_if
有一个我们可以与 SFINAE 一起使用的嵌套 type
。
实现
现在我们需要提供模板和专门化,将 SFINAE 仅用于那些具有嵌套 Vec
的类型:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
每当我们用一个类型实例化 Functor
时,编译器将尝试使用特化,它会依次实例化 has_nested_Vec
并获得一个真值,传递给 启用_if
。对于那些值为 false
的类型,enable_if
没有嵌套的 type
类型,因此特化将在 SFINAE 和将使用基本模板。
您的具体情况
在您的特定情况下,您似乎不需要专门化整个类型而只需要专门化运算符,您可以将这三个元素混合成一个:一个 Functor
调度到基于 Vec
存在的两个内部模板函数之一,消除了对 enable_if
和特征类的需要:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
关于c++ - SFINAE:编译器不选择专门的模板类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11320887/