[英]Can't understand the rule about explicit specialization declaration for menber of an unspecialized class template
最新的c++标准对非特化类模板的成员进行显式特化声明的规则如下:
在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板及其一些封闭类模板可以保持未特化,除非声明不应显式特化类成员模板,如果它封闭类模板也没有显式专门化。 在这样的显式专业化声明中,应提供后跟模板参数列表的关键字模板,而不是在成员的显式专业化声明之前的模板<>。 模板参数列表中模板参数的类型应与主模板定义中指定的相同。
老实说,我对这一段有很多困惑。 请考虑此规则下面的示例。
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <class Y>
template <>
void A<Y>::B<double>::mf2() { } // error: B<double> is specialized but
// its enclosing class template A is not
正如评论所说,成员mf2
这个显式专业化声明是mf2
,但是,我不明白为什么通过这个规则这个声明是格式错误的。 我的原因是粗体措辞,它表示如果其封闭的类模板也没有显式专门化,则声明不应显式专门化类成员模板。 但是,在此示例中,声明是mf2
的显式mf2
,它不是类成员模板,而是类模板的成员。 那么严格来说,它不符合异常的条件,为什么声明是格式错误的? 感觉这一段说不清楚。 所以进一步挖掘,我发现了CWG529的缺陷报告。
它说:
在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板及其一些封闭的类模板可能保持未特化,即相应的模板前缀可以指定模板参数- list 而不是 template<> 并且命名模板的 template-id 使用这些模板参数作为模板参数编写。 在这样的声明中,模板参数的数量、种类和类型应与主模板定义中指定的相同,并且模板参数应按照它们出现的顺序在模板ID中命名在模板参数列表中。 在命名成员的合格 ID 中,未特化的模板 ID 不应位于模板特化的名称之前。
想了想,还是觉得提案不足以解释这些案例,比如:
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template<>
template <class T>
void A<int>::B<T>::mf2(){}
首先, mf2
不是模板特化,但是模板 id B<T>
在mf2
之前,这个声明是mf2
。 它仍然无法解释这个例子:
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template<>
template <class T>
template <class U>
void A<int>::B<T>::mf1(U){}
mf1
是模板名称但不是模板 ID(即模板特化)
因此,在考虑了这些格式错误的示例之后,恕我直言,这个修改后的句子是这条规则的意图吗?
在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板和它的一些封闭类模板可能保持未特化。 在这样的显式专业化声明中,应提供后跟模板参数列表的关键字模板,而不是在成员的显式专业化声明之前的模板<>。 模板参数列表中模板参数的类型应与主模板定义中指定的相同。 在此声明中,nested-name-specifier 中未特化的每个
template-id
都应显式特化。
template <class T1> class A {
template<class T2> class B {
template<class T3>
void mf1(T3);
void mf2();
};
};
template<> // explicit specialization for `B`
template<class T>
class A<int>::B{
template<class U>
void mf1(U);
};
template<>
template<class T>
template <class U>
void A<int>::B<T>::mf1(U){}
这个例子将是格式错误的,虽然B<T>
是非特化的,但它已经被显式特化了。 这是一个很好的解释吗? 或者,如果我误读了原始规则,请解释如何理解它。
规则[temp.expl.spec]/p16递归地适用,它简单地说,除非通向它的整个链也是特化的,否则任何东西都不能特化。
我们甚至没有进入mf2
因为不可能为每个可能的A
专门化B
:
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <class Y>
template <>
void A<Y>::B<double>::mf2() { } // Not OK - can't specialize B for every possible A
template <>
template <>
void A<int>::B<double>::mf2() { } // OK - full specialization
template <class T1> class A { template<class T2> class B { template<class T3> void mf1(T3); void mf2(); }; }; template <> template <class T> void A<int>::B<T>::mf2(){}
同样的故事:不能为每个可能的A<int>::B
专门化mf2
。
最后一个带有特殊A<int>::B
例子有点令人困惑,但同样的规则仍然适用:
template <class T1> class A {
template <class T2> class B {
template<class T3>
void mf1(T3);
void mf2();
};
};
template <>
template <class T>
class A<int>::B { // explicit specialization for `B`
template<class U>
void mf1(U);
};
template <>
template <class T>
template <class U>
void A<int>::B<T>::mf1(U){} // OK (not a specialization, but an out-of-line definition)
template <>
template <class T>
template <>
void A<int>::B<T>::mf1(double){} // Not OK again, the entire chain must be specialized
template <>
template <>
template <>
void A<int>::B<double>::mf1(double){} // OK - full specialization
CWG529试图解决一个事实,即[temp.expl.spec]/p16中的措辞令人困惑,因为它在实际上没有声明此类专业化时谈论嵌套类的“专业化” 。 恕我直言,CWG 529不承认有在每一个嵌套层次专业化,只能是假设。 给出第一个例子:
template <class T1> class A {
template<class T2> class B {
template<class T3> void mf1(T3);
void mf2();
};
};
template <class Y>
template <>
void A<Y>::B<double>::mf2() { }
没有template <class Y> template <> class A<Y>::B {};
. 但是如果有一个,它就不会编译(同样,不能为每个可能的A
专门化B
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.