考虑以下片段:
struct Base { };
struct Derived : Base { };
void f(Base &) { std::cout << "f(Base&)\n"; }
template <class T = int>
void g() {
Derived d;
f(T{} ? d : d); // 1
}
void f(Derived &) { std::cout << "f(Derived&)\n"; }
int main() {
g();
}
在这种情况下,我认为函数调用f
at // 1
应该在第一阶段查找,因为它的参数类型是明确的Derived&
,从而解决f(Base&)
这是范围内唯一的一个。
Clang 3.8.0 同意我的观点 http://coliru.stacked-crooked.com/a/3cd11c152a34b3f4, but GCC 6.1.0 没有 http://coliru.stacked-crooked.com/a/2e730f9275d75b15,并推迟查找f
直到第二阶段,其中f(Derived&)
被拾起。
哪个编译器是正确的?
使用最新版本的C++标准 https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents/4653479#4653479现在n4582 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4582.pdf.
在第 14.6 节(p10)中,它说如果名称不依赖于模板参数,则名称在声明点绑定。如果它依赖于模板参数,则在第 14.6.2 节中定义。
第 14.6.2.2 节继续指出,如果任何子表达式是类型相关的,则表达式是类型相关的。
现在自从打电话给f()
取决于其参数。您查看参数类型以查看它是否取决于类型。参数为False<T>::value ? d : d
。这里第一个条件取决于类型T
.
因此我们得出结论,调用是在实例化点而不是声明点绑定的。因此应该绑定到:void f(Derived &) { std::cout << "f(Derived&)\n"; }
因此g++有更准确的实现。
14.6 名称解析[temp.res]
Para 10:
如果一个名字不依赖于模板参数(如 14.6.2 中定义),该名称的声明(或声明集)应位于该名称出现在模板定义中的范围内;该名称绑定到在该点找到的声明(或多个声明),并且此绑定不受实例化点可见的声明的影响。
14.6.2.2 类型相关表达式 [temp.dep.expr]
除下述情况外,如果满足以下条件,则表达式是类型相关的:任何子表达式都是类型相关的.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)