clang ++失败,但是g ++成功使用在赋值中的转换为const无关类型运算符 [英] clang++ fails but g++ succeeds on using a cast to const-unrelated-type operator in an assignment

查看:416
本文介绍了clang ++失败,但是g ++成功使用在赋值中的转换为const无关类型运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是一个简短的示例,可再现此 没有可行的转换与柠檬铛,但有效的g ++ 编译器行为的差异。

  #include< iostream> 

struct A {
int i;
};

#ifndef UNSCREW_CLANG
使用cast_type = const A;
#else
使用cast_type = A;
#endif

struct B {
运算符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;
}

live 在godbolt的



g ++(4.9,5.2)而clang ++(3.5,3.7)则编译它



if

  cast_type = A; 

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

,使用默认 p>

 使用cast_type = const A; 
// [...]
a = b;

在这种情况下,clang ++(3.5)blames a = b

  testling.c ++:25:9:错误:无法从'B' b $ ba = b; 
^
testling.c ++:3:8:注意:候选构造函数(隐式拷贝构造函数)
不可行:
没有从'B'到'const A& ;'for 1st argument
struct A {
^
testling.c ++:3:8:note:候选构造函数(隐式移动构造函数)
不可行:
没有从'B'到'A&'的已知转换
struct A {
^
testling.c ++:14:5:note:candidate function
运算符cast_type()const {
^
testling.c ++:3:8:注意:将参数传递给此处
struct A {
pre>

参考2011¹标准:clang ++是关于拒绝默认代码还是g ++关于接受它?

Nota bene :这是一个关于 const cast_type 上的限定符是有意义的。这是关于哪个编译器工作的标准兼容,只有



¹2014年不应该有所作为。



EDIT:



请不要使用通用c ++标记重新标记此内容。
我首先想知道哪些行为符合2011标准,并保持委员会的奉献不要破坏现有的(< 2011)代码


解决方案

所以看起来这是由这个ang错误报告 rvalue overload隐藏了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 = b; 

现在格式不正确。所以我们现在是正确的拒绝初始化。
但是这仍然是一个可怕的答案;我再次刺激CWG。我们应该在重载解析过程中
可能丢弃f(A&& amp;)。


正确的事情基于今天的标准语言,但它可能改变,因为似乎至少从ang队的分歧,这是正确的结果。因此,这可能会导致缺陷报告,我们必须等到解决后才能得出最终结论。



更新



看起来像缺陷报告2077 已根据此问题提交。


Here's a short example that reproduces this "no viable conversion" with lemon for clang but valid for g++ difference in compiler behavior.

#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;
}

live at godbolt's

g++ (4.9, 5.2) compiles that silently; whereas clang++ (3.5, 3.7) compiles it

if

using cast_type = A;

or

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

are used, but not with the defaulted

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

In that case clang++ (3.5) blames 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 { 

With reference to the 2011¹ standard: Is clang++ right about rejecting the defaulted code or is g++ right about accepting it?

Nota bene: This is not a question about whether that const qualifier on the cast_type makes sense. This is about which compiler works standard-compliant and only about that.

¹ 2014 should not make a difference here.

EDIT:

Please refrain from re-tagging this with the generic c++ tag. I'd first like to know which behavior complies to the 2011 standard, and keep the committees' dedication not to break existing (< 2011) code out of ansatz for now.

解决方案

So it looks like this is covered by this clang bug report rvalue overload hides the const lvalue one? which has the following example:

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

which fails with the same error as the OP's code. Richard Smith toward the end says:

Update: we're correct to choose 'f(A&&)', but we're wrong to reject the initialization of the parameter. Further reduced:

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

Here, [dcl.init.ref]p5 bullet 2 bullet 1 bullet 2 does not apply, because [over.match.ref]p1 finds no candidate conversion functions, because "A" is not reference-compatible with "const A". So we fall into [dcl.init.ref]p5 bullet 2 bullet 2, and copy-initialize a temporary of type A from 'b', and bind the reference to that. I'm not sure where in that process we go wrong.

but then comes back with another comment due to a defect report 1604:

DR1604 changed the rules so that

 A &&a = b;

is now ill-formed. So we're now correct to reject the initialization. But this is still a terrible answer; I've prodded CWG again. We should probably discard f(A&&) during overload resolution.

So it seems like clang is technically doing the right thing based on the standard language today but it may change since there seems to be disagreement at least from the clang team that this is the correct outcome. So presumably this will result in a defect report and we will have to wait till it is resolved before we can come to a final conclusion.

Update

Looks like defect report 2077 was filed based on this issue.

这篇关于clang ++失败,但是g ++成功使用在赋值中的转换为const无关类型运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆