为何GCC无法解析右值重载的用户定义转换运算符?
GCC无法解析右值重载的用户定义转换运算符问题
我编写了如下C++代码:
#include <iostream> #include <string> struct A { int x; int y; }; struct B { A a; ~B(){ std::cout << "deleted" << std::endl; a.x = 99; a.y = 99; } operator A & () & { std::cout << "cast A&" << std::endl; return a; } operator A () && { std::cout << "cast A" << std::endl; return a; } }; B make_b(){ return {0,1}; } int main() { const A & a = make_b(); std::cout << a.x << std::endl; std::cout << a.y << std::endl; }
这段代码在Clang编译器下输出符合预期:
cast A deleted 0 1
但在GCC编译器下编译失败,报错信息如下:
Could not execute the program Compiler returned: 1 Compiler stderr <source>: In function 'int main()': <source>:33:25: error: invalid user-defined conversion from 'B' to 'const A&' [-fpermissive] 33 | const A & a = make_b(); | ~~~~~~^~ <source>:18:5: note: candidate is: 'B::operator A&() &' (near match) 18 | operator A & () & { | ^~~~~~~~ <source>:18:5: note: passing 'B' as 'this' argument discards qualifiers <source>:33:26: error: passing 'B' as 'this' argument discards qualifiers [-fpermissive] 33 | const A & a = make_b(); | ^ <source>:18:5: note: in call to 'B::operator A&() &' 18 | operator A & () & {
问题分析
这是GCC与Clang在用户定义转换的重载决议逻辑上的差异导致的:
当执行const A& a = make_b();时,预期是调用右值限定的operator A() &&,生成临时A对象后,让const A&绑定到该临时对象(临时对象生命周期会被引用延长)。
但GCC的重载决议会优先尝试匹配返回A&的左值限定转换运算符operator A&() &——尽管该运算符要求this是左值,而make_b()返回的是右值B,调用它会违反左值限定,因此触发编译错误。
Clang则会正确排除不适用的左值限定运算符,转而选择右值限定的operator A() &&,因为其返回的临时A可以被const A&合法绑定。
解决方法
可以通过以下方式让代码在GCC上正常编译:
- 修改右值转换运算符的返回类型为
const A&,直接返回成员a的const引用:
operator const A& () && { std::cout << "cast const A&" << std::endl; return a; }
- 在
main中显式执行右值到A的转换,明确指定调用右值重载:
const A & a = static_cast<A>(make_b());
- 添加一个
const限定的左值转换运算符,作为备选匹配项:
operator const A& () const & { std::cout << "cast const A&" << std::endl; return a; }
内容的提问来源于stack exchange,提问作者bradgonesurfing
相关产品推荐
相关产品推荐

