Ben*_*hug 6 c++ generics inheritance template-specialization c++11
这个问题有点难以解释,所以我将从一个例子开始:
我有一个类模板,它将一个类型和一个整数常量作为模板参数,我有许多子类,它们来自该模板的实例化:
template <class V, int i>
struct Base
{
static void doSomething() { cout << "something " << i << endl; };
};
struct Child : public Base<int,12>
{
};
Run Code Online (Sandbox Code Playgroud)
我想将这些类与其他模板一起使用(我们称之为Test),它具有不同类型的特化.因为对于从Base的任何实例化派生的所有类,行为应该完全相同,所以我想只定义一个处理从Base派生的所有类的Test专门化.
我知道我不能直接专注于Base <V,i>,因为这不会检测子类.相反,我的第一种方法是使用Boost的enable_if和类型特征:
// empty body to trigger compiler error for unsupported types
template <class T, class Enabled = void>
struct Test { };
// specialization for ints,
// in my actual code, I have many more specializations here
template <class Enabled>
struct Test <int, Enabled>
{
static void test (int dst)
{
cout << "Test<int>::test(" << dst << ")" << endl;
}
};
// this should handle all subclasses of Base,
// but it doesn't compile
template <class T, class V, int i>
struct Test <T, typename enable_if <is_base_and_derived <Base <V,i>, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
int main (int argc, char **argv)
{
Test <int>::test (23);
Test <Child>::test (Child());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我们的想法是,专门化应该处理从Base派生的所有类,其中任意值为V和i.这不起作用,gcc抱怨道:
error: template parameters not used in partial specialization: error: ‘V’ error: ‘i’
我想问题是这种方法需要编译器尝试V和i的所有可能组合来检查它们中的任何一个是否匹配.现在,我通过向基类添加一些东西解决了这个问题:
template <class V, int i>
struct Base
{
typedef V VV;
static constexpr int ii = i;
static void doSomething() { cout << "something " << i << endl; };
};
Run Code Online (Sandbox Code Playgroud)
这样,专业化不再需要将V和i作为自由模板参数:
template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base <typename T::VV, T::ii>, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
Run Code Online (Sandbox Code Playgroud)
然后它编译.
现在,我的问题是:如何在不修改基类的情况下执行此操作?在这种情况下,这是可能的,因为我自己写了,但如果我必须在我的测试模板中处理第三方库代码,我该怎么办?有更优雅的解决方案吗?
编辑:此外,有人可以给我一个详细的解释为什么第一种方法不起作用?我有一个粗略的想法,但我更愿意有一个正确的理解.:-)
一个简单的解决方案是让Base继承另一个Base_base:
struct Base_base
{};
template <class V, int i>
struct Base
: public Base_base
{
static void doSomething() { cout << "something " << i << endl; };
};
template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base_base, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
Run Code Online (Sandbox Code Playgroud)
[已编辑]在第三方代码中,您可以使用如下技巧:
template <class V, int i>
struct Base3rdparty
{
static void doSomething() { cout << "something " << i << endl; };
};
template <class V, int i>
struct Base
: public Base3rdparty<V, i>
{
typedef V VV;
static constexpr int ii = i;
};
template <class T>
struct Test <T, typename enable_if <is_base_and_derived <Base <typename T::VV, T::ii>, T>>::type>
{
static void test (const T &dst)
{
dst.doSomething();
}
};
Run Code Online (Sandbox Code Playgroud)