【发布时间】:2018-09-11 08:28:42
【问题描述】:
如果我们考虑函数模板重载,C++ 中的标准行为是首先选择“最专业”的重载(从基本模板中)。 下一步是查看选择的重载是否明确特化。如果是,将选择匹配的显式特化。
您能否指出标准中定义第二步的地方(上一段中突出显示的部分)?
谢谢。
【问题讨论】:
标签: c++ templates language-lawyer
如果我们考虑函数模板重载,C++ 中的标准行为是首先选择“最专业”的重载(从基本模板中)。 下一步是查看选择的重载是否明确特化。如果是,将选择匹配的显式特化。
您能否指出标准中定义第二步的地方(上一段中突出显示的部分)?
谢谢。
【问题讨论】:
标签: c++ templates language-lawyer
如果我理解正确,那么您可能是从[temp.inst§4] 提到的:
除非函数模板特化显式实例化或显式特化,否则函数模板 当专业化被隐式实例化时 在需要函数定义存在的上下文中引用 或者如果定义的存在影响了语义 程序 [...]
通过否定的方式,表示 显式特化 获得优先权。
【讨论】:
来自工作草案(N4713):
17.6.6.2 函数模板的部分排序 [temp.func.order]
1. 如果函数模板被重载,函数模板特化的使用可能会产生歧义,因为模板实参推导可能将函数模板特化与多个函数模板声明相关联。重载函数模板声明的部分排序用于 以下上下文选择函数模板特化所引用的函数模板:
(1.1) — 在调用函数模板特化的重载决议期间;
(1.2) — 取函数模板特化的地址时;
(1.3) - 当放置操作员删除时,选择函数模板专业化以匹配放置操作员新;
(1.4) — 当友元函数声明、显式实例化或显式特化指的是函数模板特化时。
还有:
2 部分排序通过转换选择两个函数模板中的哪一个比另一个更专业 依次每个模板(参见下一段)并使用函数执行模板参数推导 类型。 推演过程决定一个模板是否比另一个模板更专业。 如果是这样,更专业的模板是部分排序过程选择的模板。如果两个扣除 成功后,偏序选择更受约束的模板,如 17.4.4 中的规则所述。
17.6.5.2 类模板特化的部分排序 [temp.class.order]
1 对于两个类模板的部分特化,第一个比第二个更特化,如果给定以下对两个函数模板的重写,第一个函数模板比第二个更特化 根据功能模板的排序规则(17.6.6.2): (1.1) — 两个函数模板中的每一个都具有与相应的偏特化相同的模板参数和关联的约束 (17.4.2)。
(1.2) — 每个函数模板都有一个函数参数,其类型是类模板特化,其中模板参数是函数模板中对应的模板参数 对于偏特化的 simple-template-id 的 template-argument-list 中的每个模板参数。
2 [示例:template<int I, int J, class T> class X { }; template<int I, int J> class X<I, J, int> { }; // #1 template<int I> class X<I, I, int> { }; // #2 template<int I0, int J0> void f(X<I0, J0, int>); // A template<int I0> void f(X<I0, I0, int>); // B template <auto v> class Y { }; template <auto* p> class Y<p> { }; // #3 template <auto** pp> class Y<pp> { }; // #4 template <auto* p0> void g(Y<p0>); // C template <auto** pp0> void g(Y<pp0>); // D根据功能模板的排序规则,功能模板B比功能模板A更专业,功能模板D比功能模板C更专业。 因此,部分特化#2 比部分特化#1 更特化,而部分特化#4 比部分特化#3 更特化。 ——结束示例]
[示例:
template<typename T> concept C = requires (T t) { t.f(); }; template<typename T> concept D = C<T> && requires (T t) { t.f(); }; template<typename T> class S { }; template<C T> class S<T> { }; // #1 template<D T> class S<T> { }; // #2 template<C T> void f(S<T>); // A template<D T> void f(S<T>); // B部分特化 #2 比 #1 更特化,因为 B 比 A 更特化。 ——结束示例]
【讨论】:
该标准没有正式定义显式专业化是什么。我能找到的最相关的部分是 [temp.expl.spec]/1 中的example:
[ 示例:
template<class T> class stream; template<> class stream<char> { /* ... */ }; template<class T> class Array { /* ... */ }; template<class T> void sort(Array<T>& v) { /* ... */ } template<> void sort<char*>(Array<char*>&);鉴于这些声明,
stream<char>将用作chars 的流的定义;其他流将由从类模板实例化的类模板特化处理。同样,sort<char*>将用作Array<char*>类型参数的排序函数;其他Array类型将按模板生成的函数排序。 — 结束示例 ]
【讨论】: