我正在阅读模板关键字限定符(https://www.ibm.com/support/knowledgecenter/SSPSQF_9.0.0/com.ibm.xlcpp111.aix.doc/language_ref/keyword_template_qualifier.html,以及我在哪里以及为什么必须把"模板"和"typename"关键字?),但仍有一些让我困惑的事情.
是否有可能成功编译这样的代码,但会产生两种不同的操作?
SomeObjectInstance.template some_function();
SomeObjectInstance.some_function();
Run Code Online (Sandbox Code Playgroud)
是的,您可以编写类似的内容,使其格式良好,并给出不同的结果。基本上是你自己的例子:
#include <iostream>
struct foo {
template <int = 0>
void some_function() { std::cout << "template\n"; }
void some_function() { std::cout << "non-template\n"; }
};
int main(void) {
foo f{};
f.some_function();
f.template some_function();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将打印您期望的内容。当编译器看到第一次调用 时some_function,它必须检查是否可以合成模板重载。它可以,因为我们为模板参数提供了默认参数。然后它对两个候选者进行重载解析,并且[over.match.best]/1告诉我们
给定这些定义,如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则可行函数 F1 被定义为比另一个可行函数 F2 更好的函数,然后
- F1 不是函数模板专业化,F2 是函数模板专业化,或者,如果不是这样,
我们有两个同样好的隐式转换序列(空),并且该项目符号明确表示,在其他一切都相同的情况下,非模板版本是更好的候选者。
但是当template使用关键字时,我们遵循[temp.names]/5:
以关键字 template 为前缀的名称应为 template-id,或者该名称应引用类模板或别名模板。
模板 ID 在第 1 段中具有以下语法产生式:
Run Code Online (Sandbox Code Playgroud)simple-template-id: template-name < template-argument-list > template-id: simple-template-id operator-function-id < template-argument-list > literal-operator-id < template-argument-list >
模板参数列表在上述所有内容中都是可选的。但精明的读者会注意到尖括号并未指定为可选。看来我们必须将模板成员函数命名为some_function<>. 但幸运的是我们正在进行函数调用。模板参数推导正在发生,因此可以应用[temp.arg.explicit]/3 :
...如果可以推导出所有模板参数,则可以全部省略;在这种情况下,空模板参数列表
<>本身也可以被省略。...
所以我们确实可以写f.template some_function();,并且它必须引用一个模板,根据 [temp.names]/5。这应该具有从考虑中删除非模板重载的效果。