c++ - 标准是否严格定义了该程序应如何编译?

标签 c++ language-lawyer name-lookup

构建以下程序是为了滥用 gcc/msvc 中两阶段查找的一些特性。它可以用 gcc/msvc 和 clang 很好地编译,但会导致函数 g 的返回值不同:

struct A;
struct C {};

struct D {
    D (const A &);
};

struct B {
    void f (const C&,int){x=0;};
    void f (const D&,char){x=1;};
    int x;
};

template<typename T>
int f(const A &y)
{
    B x;
    x.f(y,0);   // Line 18
    return x.x;
}

struct A
{
    operator C () const;
};

int g (const A&x)
{
    return f<int>(x);
}

https://gcc.godbolt.org/z/pqAVsU

GCC 和 MSVC 都调用 A::operator C 并返回 0,而 Clang 调用 D(const A &) 并返回 1。

根据标准,clang 是正确的,并且在 struct A 尚未声明时应该解析第 18 行的调用,这是否正确,或者这是未指定行为的情况?

最佳答案

[temp.dep.candidate ] 说,这可能与编译器失败有关(我的注释和强调):

For a function call where the postfix-expression [that is the expression that designates the function, here f] is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:

  • [Description of 2PL/ADL behaviour]

If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.

但是,x.f(y,0); 在任何时候都不依赖于T,因此上面可怕的段落并不依赖于T申请。我们处于非依赖查找的情况,由 [ temp.nondep 覆盖。 ](注意我的):

Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used. [Example follows]

整个表达式应该在 ::f 定义的上下文中解析,此时 A 不完整,其转换运算符 not可见。 Clang 是对的,GCC 和 MSVC 都是错误的。

关于c++ - 标准是否严格定义了该程序应如何编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52964883/

相关文章:

c++ - 无法显式访问命名空间范围友元

c++ - 这个 "trick"跨 DLL 边界抛出异常是个坏主意吗?

c++ - "new"operator in multiple threads cause Segmentation Fault

c++ - 重新排序 C++ 基于映射的集合的有效方法

c++ - MSVC 是否错误地处理依赖名称中的模板关键字?

c++ - 为什么对多态类的引用是多态的?

C++ 找不到命名空间外的函数

c++ - 具有父命名空间的嵌套命名空间中的重载解析

c++ - 为什么我的字符串无法在 C++ 中正确打印?

c++ - std::vector<T>::resize(n) vs reserve(n) with operator[]