【问题标题】:Conversion to `const Y` not applicable for `R&&` on clang转换为`const Y`不适用于clang上的`R&&`
【发布时间】:2012-09-28 13:55:21
【问题描述】:

以下代码使用g++ (GCC) 4.7.1 20120721 编译得很好,但是 最近构建 clang version 3.2 (trunk) 失败。

struct Y {};

struct X {
  operator const Y() const { return Y(); }
};

void f(Y&& y) {}

int main()
{
  f(X());
  return 0;
}

将转换运算符更改为operator Y() const 就足够了 使代码在两个编译器上编译。

在这种情况下,哪个编译器实际上是符合标准的?做什么 标准实际上是这样说的吗?

要求的逐字错误:

bla.cpp:14:5: error: no viable conversion from 'X' to 'Y'
  f(X());
    ^~~
bla.cpp:1:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'X' to
      'const Y &' for 1st argument
struct Y {
       ^
bla.cpp:1:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'X' to
      'Y &&' for 1st argument
struct Y {
       ^
bla.cpp:6:3: note: candidate function
  operator const Y() const { return Y(); }
  ^
bla.cpp:10:12: note: passing argument to parameter 'y' here
void f(Y&& y) {}
       ^

编辑:不幸的是,即使添加了重载

void f(const Y&) {}

仍然让 clang 选择右值引用重载,所以这个 破坏用于编译的现有代码,例如有标准 容器。

【问题讨论】:

  • 真的是“R&&”吗?您可以逐字发布诊断信息吗?
  • 作为记录,作为一个总的猜测,我会说clang就在这里。
  • @LightnessRacesinOrbit 我放弃了诊断。问题是它没有声明why转换运算符不适用。
  • 一方面,你说你不想在那个对象上使用非常量成员(返回const Y);另一方面,你说你愿意(要求Y&&)。这里有一些不一致的地方。
  • 看起来很清楚。 Y const 类型的临时对象无法绑定到 Y && 类型的引用。它可以绑定到Y const &&,但这没什么用。

标签: c++ c++11 g++ clang move-semantics


【解决方案1】:

我相信 clang 拒绝这个是正确的。将参数传递给f(Y&&) 需要两个转换步骤,第一个是您的operator const Y(),第二个是Y 的复制构造函数。我认为两者都算作用户定义的转换,并且都是隐式的,这违反了隐式转换序列仅包含一个用户定义的转换的原则。

这个Purpose of returning by const value? 包含一些关于返回const T 语义的有趣见解。

嗯,如果我尝试像现在编辑的问题那样添加重载void f(const Y&y),clang 的行为会非常奇怪。它仍然抱怨无法将X 转换为Y,甚至没有在其诊断中列出重载f(const Y& y)。但是,一旦我将重载更改为按值获取Y,即写void f(const Y y),它就会抱怨对f 的调用不明确。

这是 XCode 4.5 的 clang 报告 Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)。如果您可以使用原版 clang 重现此问题,您可能应该在 clang 邮件列表中报告此问题 - 确实似乎有一个 bug 潜伏在那里某处...

【讨论】:

  • 我认为关于两次转换的部分是正确的。
  • 我已经修改了问题,这使得整个问题变得更加困难。
  • 我也无法想象这应该是正确的。这会在几乎所有使用 STL 容器的类似代码中触发回归。
【解决方案2】:

这个例子格式不正确。

一些 N3242 引用。

8.5.3 第 4 段:

给定类型“cv1 T1”和“cv2 T2”,“cv1 T1”与引用相关如果T1T2 的类型相同,或者T1T2 的基类,则转至“cv2 T2”。如果 T1T2cv1 em> 与 cv2 的 cv 限定相同或更高。

第 5 段(项目符号标签是我的):

对“cv1T1”类型的引用由“cv2T2”类型的表达式初始化,如下所示:

  1. 如果引用是左值引用并且...
  2. 否则,引用应为对非易失性 const 类型的左值引用(即 cv1 应为 const),或者引用应为右值引用。

    一个。如果初始化表达式

    • i.是 xvalue、类纯右值、数组纯右值或函数左值,并且 "cv1 T1" 与 "cv2 T2" 引用兼容,或者
    • 二。具有类类型(即T2 是类类型),其中T1T2 没有引用相关,并且可以隐式转换为类型为“”的xvalue、类纯右值或函数左值cv3 T3",其中 "cv1 T1" 与 "cv3 T3" 引用兼容,
    • 那么引用就绑定到 ....

    b.否则,“cv1 T1”类型的临时变量会使用非引用复制初始化 (8.5) 的规则从初始化表达式创建和初始化。然后将引用绑定到临时文件。如果 T1T2 引用相关,则 cv1 的 cv-qualification 应与 cv2 相同或更高的 cv-qualification。 ...

函数参数初始化,T1YT2Xcv1cv2均为空。 1 出来了:引用是右值引用,而不是左值引用。 2.a.i.已失效:XY 的引用不兼容。 2.b。因为从X 类型的纯右值复制初始化Y 涉及到两个用户定义的转换:转换函数和Y 的复制构造函数。 (确切的禁止在 13.3.3.1p4 中。)

对于案例 2.a.ii.,“cv3 T3”的明显选择是 const Y,但这并不好,因为 Y 与 @987654359 不兼容@。您可能会争辩尝试 T3Y 并且 cv3 为空,但随后您又需要 Y 的复制构造函数作为第二个隐式用户定义转换。

【讨论】:

  • 你是否也在考虑有两个重载的情况?这与为什么该示例格式错误并没有真正的关系,但它会解决真正的问题。
猜你喜欢
  • 2013-07-29
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多