【问题标题】:Is it a bug in clang when process reference initialization进程引用初始化时是否是clang中的错误
【发布时间】:2020-07-25 03:23:46
【问题描述】:
#include <iostream>
struct B;
struct A{
  operator B&&() const;
};
struct B{
  B(A const&){

  }
  B() {}
};
int main(){
    A a;
    B&& rf = a;  //#1
}

B g;
A::operator B&&() const {  
    std::cout<<"execute\n";
    return std::move(g);
}

考虑上面的代码,结果是here#1 的引用绑定遵循以下规则:

否则,引用应为对非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应为右值引用。

  • 如果初始化表达式
  • 是右值(但不是位域)或函数左值,“cv1 T1”与“cv2 T2”引用兼容,或者
  • 具有类类型(即T2是类类型),其中T1与T2没有引用相关,可以转换为“cv3 T3”类型的右值或函数左值,其中“cv1 T1”是与“cv3 T3”参考兼容(参见[over.match.ref]),

那么在第一种情况下的初始化表达式的值和在第二种情况下的转换结果称为转换后的初始化程序。如果转换后的初始值设定项是纯右值,则将其类型 T4 调整为类型“cv1 T4”([conv.qual])并应用临时实现转换。在任何情况下,引用都绑定到生成的 glvalue(或适当的基类子对象)。

  • 否则:
  • 如果 T1 或 T2 是类类型,并且 T1 与 T2 没有引用相关,则使用通过用户定义的转换([ dcl.init]、[over.match.copy]、[over.match.conv]);如果相应的非参考复制初始化格式错误,则程序格式错误。调用转换函数的结果,如针对非引用复制初始化所描述的,然后用于直接初始化引用。对于这种直接初始化,不考虑用户定义的转换。

根据上述规则的结构,If 分支的第二个子弹对于B&amp;&amp; rf = a; 就足够了,因此A 类的operator B&amp;&amp;() const 是唯一的候选转换函数,换句话说,只要满足if的情况,那么otherwise的分支就永远不会下架了。

GCC 的结果证明了这些规则所说的内容,但是Clang 抱怨执行引用绑定的转换函数不明确(Clang 似乎将各自分支中的两个转换函数都视为候选函数)。是clang的bug吗?

尽管如此,case

#include <iostream>
struct B;
struct A{
  operator B&&() const;
};
struct B{
  B(A&){

  }
  B() {}
};
int main(){
    A a;
    B&& rf = a;  //#1
}

B g;
A::operator B&&() const {  
    std::cout<<"execute\n";
    return std::move(g);
}

GCC 还是同意operator B&amp;&amp;() const 是执行引用绑定的唯一转换函数。

【问题讨论】:

标签: c++ c++17 language-lawyer


【解决方案1】:

是的,你选对了[dcl.init.ref] §5.2.1.2

否则,引用应为对非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应为右值引用。

  • 如果初始化表达式
  • 是一个右值 [...]
  • 具有类类型(即T2是类类型),其中T1与T2没有引用相关,可以转换为“cv3 T3”类型的右值或函数左值,其中“cv1 T1”是与“cv3 T3”参考兼容(参见[over.match.ref]),

引用初始化的意图是首先尝试直接绑定(定义在[dcl.init.ref]部分的最后一个规范句子中,简而言之:直接绑定发生在初始化器和引用是引用相关的,或者如果有一个转换函数,其结果类型是与初始化引用相关的引用)。所以这是一个 Clang 错误,这在标准中肯定不是一个未解决的问题。

(可能引起怀疑的站点开放问题(CWG2028)与某些“直接绑定”可能涉及临时实现的事实有关,因此这些情况不应是直接引用绑定,而是对结果的间接绑定用户定义的转换。)

【讨论】:

  • cwg2028 似乎与我的问题相同。然而,在该提案的最后一句话中,它说CWG agreed that 11.6.3 [dcl.init.ref] should be changed to consider converting constructors in this case. 但是为了实现这句话所说的,最新标准没有变化,即consider converting constructor
  • @jackX 不,不是。在您的情况下,转换函数返回一个glvalue,而在cwg2028 中,转换函数返回一个prvalue。只有返回 glvalues 的转换函数才能用于直接绑定(显然)
  • @jackX 看看 cwg2108,它就在 cwg2028 的下面。
猜你喜欢
  • 1970-01-01
  • 2019-02-27
  • 2016-07-18
  • 2021-09-10
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 2020-08-14
  • 1970-01-01
相关资源
最近更新 更多