c++ - 标准是否严格定义了该程序应如何编译?
问题描述
以下程序是为了滥用 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 ] 说,这可能与编译器故障有关(注释和强调我的):
对于后缀表达式[即指定函数的表达式,此处
f
] 是从属名称的函数调用,使用通常的查找规则([basic.lookup.unqual]、[basic.lookup. argdep]) 除了:
- [2PL/ADL 行为描述]
如果调用格式错误或找到更好的匹配,则在关联命名空间中的查找考虑所有翻译单元中这些命名空间中引入的具有外部链接的所有函数声明,而不仅仅是考虑在模板定义和模板中找到的那些声明实例化上下文,则程序具有未定义的行为。
但是,x.f(y,0);
不依赖于T
任何一点,因此上面的可怕段落不适用。我们是在非依赖查找的情况下,由 [ temp.nondep ] 覆盖(注意我的):
模板定义中使用的非依赖名称是使用通常的名称查找找到的,并在使用它们时绑定。[示例如下]
整个表达式应该在::f
' 定义的上下文中解析,此时A
不完整并且其转换运算符不可见。Clang 是对的,而 GCC 和 MSVC 都是错误的。
推荐阅读
- wpf - 如何在多个线程中访问 UI 元素?
- haml - 在没有 Rails 的情况下使用 HAML,如何在部分下嵌套元素?
- python - 警告:不推荐使用的属性“
对象“<__main__.Tab >object at”的“被访问,它将在未来的版本中删除 - java - 有没有一种干净的方法可以使用 Java 从正则表达式中获取字符串文字?
- javascript - 从 Javascript 中的 JSON 文件中读取非静态密钥
- flutter - 我无法获取数据打开天气图
- python - 如何编写最优的嵌套递归函数
- sockets - 如何让kline node js命令生效?
- reporting-services - ReportProcessingException:数据集的查询执行失败
- bash - Azure Devops-如何验证组织中是否存在团队(Azure CLI 或 Azure Bash)