【问题标题】:Is it strictly defined by the standard how this program should compile?标准是否严格定义了该程序应如何编译?
【发布时间】:2018-10-24 08:59:25
【问题描述】:

以下程序是为了滥用 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 &amp;) 并返回 1。

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

【问题讨论】:

  • @Predelnik 有些人比其他人更容易触发,但一旦问题得到解决,表现得更好的人就会挂起 DV。
  • @Quentin 好的。感谢您的编辑。我删除了我的评论,因为它当时很火爆。
  • 哦,我明白了,问题的关键部分仍然只在链接的 Godbolt 输出中可见...
  • 我在这里没有看到名称查找问题。

标签: c++ language-lawyer name-lookup


【解决方案1】:

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

对于 postfix-expression [即指定函数的表达式,此处为 f] 是从属名称的函数调用,使用通常的查找规则 ( [basic.lookup.unqual], [basic.lookup.argdep]) 除了:

  • [2PL/ADL 行为描述]

如果调用格式错误或会找到更好的匹配,则在关联命名空间中的查找会考虑所有翻译单元中这些命名空间中引入的具有外部链接的所有函数声明,而不仅仅是考虑到模板定义和模板实例化上下文中的那些声明,那么程序具有未定义的行为

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

模板定义中使用的非依赖名称是使用通常的名称查找找到的,并在它们被使用的地方绑定。 [示例如下]

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

【讨论】:

    【解决方案2】:

    程序格式错误,不需要诊断,根据[temp.res]/8

    可以在任何实例化之前检查模板的有效性。 [ 注意:知道哪些名称是类型名称允许每个 以这种方式检查的模板。 —— 尾注 ]程序是 格式错误,不需要诊断,如果:

    • ...

    • 在假设的实例化中对这种结构的解释不同于对 模板的任何实际实例中的相应构造。 [ 注意:这可能发生在以下情况:

      • 在非依赖名称中使用的类型在定义模板时是不完整的,但在定义模板时是完整的 执行实例化,或

      • ...

    • ...

    在您的程序中,y 是一个非依赖名称,其类型 Af 的定义中不完整,但在实例化 f&lt;int&gt; 时完整,因此适用上述规则。

    【讨论】:

      猜你喜欢
      • 2014-02-01
      • 2015-12-02
      • 2018-02-11
      • 2013-08-27
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      • 2012-03-14
      相关资源
      最近更新 更多