A在类层次结构中使用了一个模板类,B::C_#其专门方法create()是A:
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
请帮助可怜的生物克服他的麻烦。
还尝试在 special 中进行模板方法专业化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); }
解决方案
好的,所以我最终A在C_0模板级别使用C_0参数列表对整个模板类进行了部分专业化:
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实例化)的实例在模板中使用,因此不会看到at 的特化A_C_0A_AC_0等级。这就是为什么在那个级别它调用void create(). 由于开销太大,也无法移动A_到 的级别。C_0_specialized
好在班级A不大,但还是最好只专攻void create()。
我发现这个资源对于解释模板的显式和部分专业化之间的差异非常有用。