【问题标题】:Why not specialize function templates? (Q&A)为什么不专门化功能模板? (问答)
【发布时间】:2021-06-12 15:59:52
【问题描述】:

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

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

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

【问题讨论】:

  • 额外的问题当然是“f(nullptr) 打印什么?”
  • @MSalters nullptr_t 不是 T*,最好的 C++!

标签: c++ pointers templates overloading template-specialization


【解决方案1】:

如果您的答案是 3,那么恭喜,您可以跳过此问答。

对于其他所有人:

我个人认为输出应该是2,如果你到了这一点,我猜你也是。
现在让我们深入一点。

名称 f 被 void f(T)void f(T*) 两个函数模板重载。请注意,重载决议只考虑函数模板,而不是显式特化void f&lt;&gt;(int*)!对于重载解析,首先我们推导出每个函数模板的模板参数,第一个得到T = int *,第二个得到T = int

这两个函数模板都是可行的,但哪一个最好?根据[over.match.best]§16.3.3¶1 的说法,如果函数模板更专业,则它比另一个函数模板更匹配:

一个可行的函数 F1 被定义为比另一个更好的函数 可行的函数 F2 if (...) F1 的函数模板更 根据偏序,比 F2 的模板更专业 17.5.6.2 中描述的规则

这里引用偏序的过程有点长,不是这个问题的关键。但总而言之,f(T*) 接受的任何内容也将被f(T) 接受,但反之则不然。所以f(T*)更专业。

现在我们知道函数模板void f(T*) 是通过重载决议选择的,我们可以开始考虑专门化。 void f&lt;&gt;(int*) 是哪个函数模板的特化? [temp.expl.spec]§17.7.3¶3:

函数模板的声明 (...) 被显式声明 专门的应先于显式的声明 专业化。

因此,显式特化 void f&lt;&gt;(int*)void f(T) 的特化,因为这是在它之前的唯一函数模板声明。然而,重载分辨率选择了另一个函数模板void f(T*),我们改为调用隐式实例化它的特化,打印 3。

更多信息请参考 Herb Sutter 的article

【讨论】:

    猜你喜欢
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 2018-11-16
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多