条件运算符的返回类型和两阶段查找
Conditional operator's return type and two-phase lookup
考虑以下片段:
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();
}
在这种情况下,我认为// 1
处对f
的函数调用应该在第一阶段查找,因为它的参数类型明确为Derived&
,因此可以解析为范围中唯一的f(Base&)
。
Clang 3.8.0同意我的观点,但GCC 6.1.0不同意,并将f
的查找推迟到第二阶段,即f(Derived&)
的查找。
哪个编译器是对的?
使用最新版本的C++标准当前为n4582。
在第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〕
第10段:
如果一个名称不依赖于模板参数(如14.6.2中所定义),则该名称的声明(或声明集)应在该名称出现在模板定义中时的范围内;名称绑定到在该点找到的声明,并且该绑定不受实例化时可见的声明的影响。
14.6.2.2依赖于类型的表达式[temp.dep.expr]
除以下所述外,如果任何子表达式都是类型依赖的,则表达式是类型依赖性的。
我认为gcc(顺便说一句,还有visualstudio)在这方面做得很好。
n4582,§14.6.2.2
除以下描述外,如果任何子表达式都是类型依赖的,则表达式是类型依赖性的。
在T{} ? d : d
中,有3个子表达式:
T{}
,明显的类型依赖性d
(2次),不依赖于类型
由于存在与类型相关的子表达式,并且三元运算符未出现在§14.6.2.2中的异常列表中,因此它被视为与类型相关。
根据c++草案(n4582)§14.7.1.5:
除非函数模板专门化已明确实例化或显式专用的函数模板当特殊化为在需要函数定义存在的上下文中引用。除非调用是对函数模板显式专门化或显式专用类模板的成员函数函数模板或的成员函数的默认参数类模板在调用函数时被隐式实例化在需要默认参数值的上下文中。
我认为gcc对此更正确。
例如,如果您创建void g()
的专用版本,那么两个编译器都会执行相同的操作。
- 正在查找文档以获得PS4平台的C++中的设备信息
- 在C++中查找文件
- 模板元程序查找相似的连续类型名称
- 在UNIX系统中使用DIR查找文件的字节大小
- 设置::查找和查找之间的性能差异<algorithm>
- 如何在 c++98 中通过特定字段在 QList 中查找对象?
- 联合查找算法(查找周期),不使用 malloc
- 如何使用 Clang 查找所有成员字段读/写?
- 查找哪个代码段比另一个代码段快
- 动态链接到 c++ 静态成员字段时符号查找失败
- 从地址中查找堆或堆块或段
- 无法使用查找窗口查找窗口
- 如何在C++中编写一段代码以查找系统路径上文件的完整路径
- 通过 2 个字段查找特定对象的向量元素
- 如何查找和填充第三方源的 Flash 字段
- 您查找段错误原因的方法是什么?
- 查找无序后继递归代码中的段错误
- 在类文件和缓冲区中查找段故障
- 在这段代码中查找3个错误,这些错误都会导致无限循环
- 在容器中查找具有给定字段最小值的元素的最紧凑的方法