dec*_*uto 9 g++ conversion-operator language-lawyer c++11 clang++
这是一个简短的例子,用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;
}
Run Code Online (Sandbox Code Playgroud)
住在Godbolt的
g ++(4.9,5.2)默默地编译; 而clang ++(3.5,3.7)编译它
如果
using cast_type = A;
Run Code Online (Sandbox Code Playgroud)
要么
using cast_type = const A;
// [...]
a = b.operator cast_type ();
Run Code Online (Sandbox Code Playgroud)
使用, 但没有默认
using cast_type = const A;
// [...]
a = b;
Run Code Online (Sandbox Code Playgroud)
在那种情况下,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 {
Run Code Online (Sandbox Code Playgroud)
参考2011¹标准:clang ++是关于拒绝默认代码还是g ++接受它的权利?
Nota bene:这不是关于这个const
限定符是否cast_type
有意义的问题.这是关于哪个编译器符合标准,并且仅与此有关.
¹2014在这里不应该有所作为.
编辑:
请不要使用通用c ++标记重新标记它.我首先想知道哪种行为符合2011标准,并且not to break existing (< 2011) code
暂时保留委员会对ansatz 的奉献精神.
所以看起来这个被这个clang bug报告覆盖了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);
}
Run Code Online (Sandbox Code Playgroud)
失败的错误与OP的代码相同.理查德史密斯到最后说:
更新:我们选择"f(A &&)"是正确的,但我们拒绝参数的初始化是错误的.进一步减少:
Run Code Online (Sandbox Code Playgroud)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改变了规则
Run Code Online (Sandbox Code Playgroud)A &&a = b;
现在形象不对.所以我们现在正确拒绝初始化.但这仍然是一个可怕的答案; 我再次向CWG提出了批评.我们应该在重载决策期间丢弃f(A &&).
所以看起来clang在技术上是基于今天的标准语言做正确的事情,但它可能会改变,因为至少来自clang团队似乎存在分歧,这是正确的结果.所以这可能会导致缺陷报告,我们将不得不等到它得到解决才能得出最终结论.
更新
看起来基于此问题提交了缺陷报告2077.