【发布时间】:2013-10-16 17:22:30
【问题描述】:
在B::C_#的类层次结构中使用了一个模板类A,它专门用于A的方法create():
template <typename T>
class A
: public std::map<std::string, double (T::*)() const>
{
...
void create();
...
};
template <typename T>
void A<T>::create()
{ assert(false); }
这些子类之一C_#(假设是C_0)直到最近都很棒。一切都很顺利,直到C_0 决定成为模板。除了 create() 专业化之外,他一切都顺利进行。它尝试通过以下方式专门化create():
template<class N1, class N2>
class C_0: public B<N1, N2>
{
...
}
...
template<class N1, class N2>
some_namespace::A< some_namespace::C_0<N1, N2> >
some_namespace::C_0<N1, N2>::A_;
template <>
void some_namespace::A< C_0<N1, N2> >::create() // line 1151
{
blah_(&C_0<N1, N2>::get_stuff);
}
但是C_0 迄今为止的尝试都失败了:
C_0.h:1151:45: error: 'N1' was not declared in this scope
C_0.h:1151:49: error: 'N2' was not declared in this scope
C_0.h:1151:51: error: template argument 1 is invalid
C_0.h:1151:51: error: template argument 2 is invalid
C_0.h:1151:53: error: template argument 1 is invalid
C_0.h:1151:63: error: 'create' is not a template function
请帮助可怜的生物克服他的麻烦。
还尝试在专门的C_0中做模板方法专门化:
namespace some_namespace
{
class C_0_specialized: public C_0<double_t, size_t>
{};
template <>
void A<C_0_specialized>::create()
{
blah_(&C_0_specialized::get_stuff);
}
}
这次它编译了,但是调用了原来的方法,也就是void A<T>::create() { assert(false); }
解决方案
好的,所以我最终在 C_0 模板级别中使用 C_0 参数列表对整个模板类 A 进行了部分特化:
template<class N1, class N2>
class A< C_0<N1, N2> >
{
...
void create()
{
blah_(&C_0<N1, N2>::get_stuff);
}
...
}
原因是:1)模板方法的部分特化是不允许的,所以不能只特化void create(),当类被部分特化时,所有的方法和变量都必须在特化中重新定义; 2) 模板方法void create() 的显式特化在C_0 级别内是不可能的,因为A 依赖于C_0 模板参数列表; 3) 将void create() 特化移动到C_0_specialized,因为C_0_specialized 模板参数列表已解析,所以它可以显式特化,这是不可能的,因为A 的实例(在上面的代码中实例化为A_ ) 在模板C_0 中使用,因此A_ 不会在C_0 级别看到A 的特化。这就是为什么在那个级别它调用void create() 的基本版本。由于开销太大,也无法将A_ 移动到C_0_specialized 的级别。
好在A 的类不大,但最好只专注于void create()。
我发现this resource 对于解释模板的显式和部分特化之间的区别非常有用。
【问题讨论】:
-
编译器是对的。您需要传递实际类型而不是
N1和N2。这是你的选择。 -
@stefan 有没有办法在模板 C_0 中获得正确的语法,而不是将其移至 C_0 的具体实例?