很抱歉在最后一个答案中误导了您,我想了一会儿会更简单。所以我会尝试在这里提供一个完整的解决方案。解决此类问题的一般方法是编写一个 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 将丢弃该重载,剩下的唯一选项将是省略号。所以现在我们有一个 trait 来询问任何类型是否有嵌套的 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有一个嵌套的type我们可以与 SFINAE 一起使用。
实施
现在我们需要提供模板和专门化,以便仅将 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 并获得一个真值,传递给enable_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);
}
};