9

这是一个简短的示例,它使用柠檬为 clang 重现了这种“不可行的转换”,但对于 g++编译器行为的差异有效。

#include <iostream>

struct A { 
    int i; 
};

#ifndef UNSCREW_CLANG
using cast_type = const A;
#else 
using cast_type = A;
#endif

struct B {
    operator cast_type () const {
        return A{i};
    }
    int i;
}; 

int main () { 
    A a{0};
    B b{1};

#ifndef CLANG_WORKAROUND
    a = b;
#else    
    a = b.operator cast_type ();
#endif    

    std::cout << a.i << std::endl;    

    return EXIT_SUCCESS;
}

在 Godbolt's

g++ (4.9, 5.2) 静默编译;而 clang++ (3.5, 3.7) 编译它

如果

using cast_type = A;

或者

using cast_type = const A;
// [...] 
a = b.operator cast_type ();

被使用, 但不与默认值一起使用

using cast_type = const A;
// [...] 
a = b; 

在那种情况下 clang++ (3.5) 责备a = b

testling.c++:25:9: error: no viable conversion from 'B' to 'A'
    a = b;
        ^
testling.c++:3:8: note: candidate constructor (the implicit copy constructor) 
not viable:
      no known conversion from 'B' to 'const A &' for 1st argument
struct A { 
       ^
testling.c++:3:8: note: candidate constructor (the implicit move constructor) 
not viable:
      no known conversion from 'B' to 'A &&' for 1st argument
struct A { 
       ^
testling.c++:14:5: note: candidate function
    operator cast_type () const {
    ^
testling.c++:3:8: note: passing argument to parameter here
struct A { 

参考 2011¹ 标准:clang++ 拒绝默认代码是正确的,还是 g++ 正确接受它?

Nota bene:这不是关于那个const限定词是否cast_type有意义的问题。这是关于哪个编译器符合标准并且仅关于那个

¹ 2014 在这里不应该有所作为。

编辑:

请不要使用通用 c++ 标记重新标记它。我首先想知道哪种行为符合 2011 年标准,并且暂时让委员会的奉献精神远离not to break existing (< 2011) codeansatz。

4

1 回答 1

9

所以看起来这被这个clang错误报告覆盖了rvalue重载隐藏了const lvalue one?其中有以下示例:

struct A{};
struct B{operator const A()const;};
void f(A const&);
#ifdef ERR
void f(A&&);
#endif
int main(){
  B a;
  f(a);
}

失败并出现与 OP 代码相同的错误。理查德史密斯在最后说:

更新:我们选择'f(A&&)'是正确的,但是我们拒绝初始化参数是错误的。进一步减少:

  struct A {};
  struct B { operator const A(); } b;
  A &&a = b;

这里,[dcl.init.ref]p5 bullet 2 bullet 1 bullet 2 不适用,因为 [over.match.ref]p1 找不到候选转换函数,因为“A”与“const A”不兼容。所以我们进入 [dcl.init.ref]p5 bullet 2 bullet 2,并从 'b' 复制初始化 A 类型的临时变量,并将引用绑定到它。我不确定在那个过程中我们哪里出错了。

但由于缺陷报告 1604而返回另一条评论:

DR1604 更改了规则,以便

 A &&a = b;

现在格式不正确。所以我们现在拒绝初始化是正确的。但这仍然是一个糟糕的答案;我再次刺激了 CWG。我们可能应该在重载决议期间丢弃 f(A&&)。

因此,从技术上讲,clang 似乎在基于标准语言做正确的事情,但它可能会改变,因为至少 clang 团队似乎不同意这是正确的结果。所以大概这会导致一个缺陷报告,我们必须等到它得到解决才能得出最终结论。

更新

看起来缺陷报告 2077是基于此问题提交的。

于 2015-11-12T15:00:15.033 回答