如果您能够使用 C++11(或<type_traits>
一般情况下),以下也是一种可能的解决方案,不仅涵盖 types T : Base<T>
,即 CRTP 的实例,而且还T : Base<U>
没有其他基类,如您的示例中所要求的。
#include <iostream>
#include <type_traits>
template <typename T>
struct Base
{
typedef T base_value_type;
};
struct Derived : public Base<int>
{
};
template <typename T, typename = T>
struct IsDerived
{
static const bool value = false;
};
template <typename T>
struct IsDerived<T, typename std::enable_if<std::is_base_of<Base<typename T::base_value_type>, T>::value, T>::type>
{
static const bool value = true;
};
template <typename T>
void Caller(const T&)
{
std::cout << IsDerived<T>::value << std::endl;
}
int main()
{
Caller(double()); // false
Caller(Derived()); // true
return 0;
}
请注意typedef T base_value_type
- 可以随意调用。这个想法是每个T
派生的类型Base<U>
都可以利用基础模板参数的知识。有没有没关系T == U
。尝试替换第二个参数将失败,只要您传入一个T
没有的参数typedef T base_value_type
,因此不会生成此特定参数的特化T
。
编辑:处理您的评论后,并受到我发布的线程的启发,我试图U
在检查一些时间类型时以某种方式提取一些基本参数T : Base<U>
。我认为这不能以您想要的方式完成,即您通过任何内容T
然后提取U
。但是,您可以做两件事。
简单的解决方案:如果您可以控制派生类的实现方式,而不是typedef
在基类中添加 a,只需在派生类中添加相应的 typedef:
template <typename BaseParamType>
class Derived : public Base<BaseParamType>
{
public:
typedef BaseParamType base_param_type;
}
或者,如果您不希望派生类也成为类模板,只需将类型硬编码到类型中(您已经知道基本参数的类型):
class Derived : public Base<int>
{
public:
typedef int base_param_type;
}
更多涉及的解决方案:至少对于可能的预期子集U
,您可以执行以下操作:
template <typename DerivedType,
typename BaseParamType = DerivedType,
bool = std::is_base_of<Base<BaseParamType>, DerivedType>::value>
struct Extract
{
typedef BaseParamType type;
};
template <typename T, typename U>
struct Extract<T, U, false>;
int main()
{
Extract<DerivedCRTP>::type; // CRTP - trivial
Extract<Derived, int>::type; // type == int, Derived is derived from Base<int>
Extract<Derived, double>::type; // compile-time error, undefined template
return 0;
}
这不像将某个类型的实例传递给推导模板函数并神奇地拥有它那样方便,但您至少可以测试某个类型是否T
派生自Base<U>
,如果不是,则获得编译时错误。