无法理解关于非专用类模板的 menber 显式专用化声明的规则
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
的显式专用化,它不是类成员模板,而是类模板的成员。所以严格来说,它不符合例外的条件,为什么声明格式不正确?我觉得这一段不清楚。因此,进一步挖掘,我发现了有缺陷的报告,即CWG529。
它说:
在类模板的成员或出现在命名空间范围的成员模板的显式专用化声明中,成员模板及其某些封闭类模板可能保持非专用化,也就是说,相应的模板前缀可以指定模板参数列表而不是模板<>并且使用这些模板参数作为模板参数编写命名模板的模板 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
不是模板专用化,但是模板 idB<T>
在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(即模板专用化)
那么在思考了这些格式错误的例子之后,恕我直言,这个修改后的句子是这个规则的意图吗?
在类模板的成员或出现在命名空间作用域的成员模板的显式专用化声明中,成员模板及其某些封闭类模板可能保持非专用化状态。在这种明确的专用化声明中,应在成员的显式专用声明之前提供关键字模板后跟模板参数列表<>而不是模板。模板参数列表中的模板参数类型应与主模板定义中指定的类型相同。在此声明中,嵌套名称说明符中非专用名称说明符中的每个
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
CWG 529试图解决这样一个事实,即[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
)。
- .cpp和.h文件中的模板专用化声明
- 调用专用模板时出错"no matching function for call to [...]"
- 模板专用化(按容器):value_type
- 静态数据成员模板专用化的实例化点在哪里
- 特征 3 类的模板专用化
- Visual Studio 2017 不允许我创建 C++ 专用模板
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 具有常量引用参数的函数模板专用化
- 使用其他模板的模板专用化
- 使用专用显卡进行 OpenGL 渲染时帧速率较低
- 嵌套模板显式专用化
- 如何检查模板专用化是否是基本模板的子类?
- C++:部分模板专用化用例
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 使用对象的基类部分模板专用化对对象进行哈希处理::哈希
- 在 C++20 中是否不再允许在 std 中对程序定义类型的函数模板进行专用化?
- 为什么依赖模板类型在部分专用化中不可推导?
- 如何为静态常量模板化专用整数值分配存储
- 模板类的部分模板专用化,如 std::function
- 合并一组模板专用化