【发布时间】:2016-06-01 08:48:05
【问题描述】:
考虑以下 sn-p:
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 agrees with me,但GCC 6.1.0 doesn't,并将f 的查找推迟到第二阶段,此时f(Derived&) 被拾取。
哪个编译器是对的?
【问题讨论】:
-
将此列为核心问题。
-
@Columbo 我倾向于认为规则在这种情况下可以正常工作。如果我在将来某个时候将条件表达式更改为
T{} ? d : e,我不希望f的名称查找突然改变并包含更多候选人。特别是如果e是一个使用d初始化的引用,但将来可能会更改为引用其他内容。此外,即使arg是非依赖的,也能够使用类似f((always_void<T>() , arg))的函数调用强制进行依赖名称解析,这对我来说似乎更像是一个特性而不是一个错误。 -
@bogdan 考虑到条件运算符已经有自己的规则来推断其结果的类型,并且条件的类型不会干扰,我看不出有什么令人惊讶的。为了确定表达式是否依赖,可以简单地忽略第一个操作数。另一方面,逗号运算符的结果类型取决于两个操作数,因此这种快捷方式是不可能的,因此您的示例仍然可以正常工作(我同意这是一个非常有用的功能)。
-
@Quentin 啊,所以你认为条件应该被挑出来,因为它不能被重载。这是一个很好的观点。 (一开始我的印象不同,抱歉。)我能想到的一个潜在问题是,使这样的条件表达式不依赖于类型会使
noexcept(T{} ? d : d)之类的东西不依赖于值,这是不正确的(@ 987654337@ 的构造函数可能会抛出),因此需要添加一些额外的特殊情况。不确定是否值得,但现在我认为值得考虑。我想得越多,你的问题就越有趣! -
@bogdan 这不是特定于条件运算符的。
noexcept(typeid(T{}))也不依赖于价值。
标签: c++ language-lawyer compiler-bug name-lookup dependent-name