首页 > 解决方案 > 为什么不专门化功能模板?(问答)

问题描述

我将尝试组织这个问题,作为问答,并希望有同事能从中有所收获。

首先,让我们先回答一个简单的问题,这个程序的输出是什么?

#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 );
}

标签: c++pointerstemplatesoverloadingtemplate-specialization

解决方案


如果您的答案是 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 的文章


推荐阅读