c++ - 为什么不专门化功能模板?(问答)
问题描述
我将尝试组织这个问题,作为问答,并希望有同事能从中有所收获。
首先,让我们先回答一个简单的问题,这个程序的输出是什么?
#include <iostream>
template<class T>
void f(T) { std::cout << 1; }
template<>
void f<>(int*) { std::cout << 2; }
template<class T>
void f(T*) { std::cout << 3; }
int main() {
int *p = nullptr;
f( p );
}
解决方案
如果您的答案是 3,那么恭喜,您可以跳过此问答。
对于其他所有人:
我个人认为输出应该是2,如果你到了这一点,我猜你也是。
现在让我们深入一点。
名称 f 被两个函数模板void f(T)
和void f(T*)
. 请注意,重载决议只考虑函数模板,而不是显式特化void f<>(int*)
!对于重载决议,首先我们推导出每个函数模板的模板参数,并T = int *
为第一个和T = int
第二个获取。
两种功能模板都是可行的,但哪一种最好呢?根据[over.match.best]§16.3.3¶1,如果函数模板更专业,则它比另一个函数模板更匹配:
如果 (...) 根据 17.5.6.2 中描述的偏序规则,F1 的函数模板比 F2 的模板更专业,则一个可行函数 F1 被定义为比另一个可行函数 F2 更好的函数
部分排序的过程在这里引用有点长,并不是这个问题的关键。但总而言之,任何被 接受的东西f(T*)
也会被 接受f(T)
,但不是相反。所以f(T*)
更专业。
现在我们知道函数模板void f(T*)
是通过重载决议选择的,我们可以开始考虑专门化。哪个功能模板是void f<>(int*)
专门化的?[temp.expl.spec]§17.7.3¶3:
显式特化的函数模板 (...) 的声明应在显式特化的声明之前。
所以显式特化 voidf<>(int*)
是 的特化void f(T)
,因为这是它之前唯一的函数模板声明。然而,重载决议选择了另一个函数模板,void f(T*)
我们改为将隐式实例化称为它的特化,打印 3。
更多内容请参考 Herb Sutter 的文章
推荐阅读
- arduino - 如何在 arduino 中延迟压电蜂鸣器的声音
- python - 从 2D 列表到 dict 时解包的值太多(预期为 2)?(Python)
- javascript - 无法使用 node.js 中的应用程序从扩展模块调用基本模块
- javascript - 为什么 this.key 在 JavaScript 中不能正常工作?
- matlab - 根据给定的输入数字更新 gui 表
- python - 关闭屏幕会杀死 tkinter,从而杀死我的 Python 闹钟。怎么修?
- php - 尝试从数组中创建具有输入字段名称的变量但不工作
- java - 解析日期字符串返回错误的月份
- vb.net - VB.NET 如何在将其捕获为热键时避免第一次按键?
- go - 在 gcp 云功能中使用 gorillamux