You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何直接初始化st对象时调用const左值引用限定转换函数而非右值版本?

问题:为何st s = st(foo());调用拷贝构造而非移动构造?

我定义了两个类st和foo:

struct st {
    st() = default;

    st(const st&) {
        std::cout << "copy ctor." << std::endl;
    }

    st(st&&) {
        std::cout << "move ctor." << std::endl;
    }
};

struct foo {
    operator st&() & {
        return s;
    }

    operator const st&() const& {
        return s;
    }

    operator st&&() && {
        return std::move(s);
    }

    operator const st&&() const&& {
        return std::move(s);
    }

    st s;
};

当执行如下代码时:

st s = st(foo());

程序调用了st的拷贝构造函数。

为何它没有调用foo的右值引用限定转换函数,进而使用st的移动构造函数?


补充说明:

  • MSVC可编译此代码,但GCC和Clang无法编译。
  • 移除const & operator后,MSVC、GCC、Clang均可编译。
  • 移除&& operator后,MSVC和GCC可编译,但Clang无法编译。
  • 移除&& operator和const && operator后,三款编译器均可编译。

解答

这是重载决议规则与编译器实现差异共同作用的结果,拆解来看:

1. 核心:右值对象的转换运算符重载决议

foo()是临时右值,编译器需要从foo的四个转换运算符中挑选最优匹配:

  • operator st&() &:左值限定,直接排除(右值无法绑定到左值引用的this)
  • operator const st&() const&:const左值限定,右值可以绑定到const左值引用的this,属于候选
  • operator st&&() &&:右值限定,完全匹配右值对象的this,属于候选
  • operator const st&&() const&&:const右值限定,也能匹配右值对象的this,属于候选

2. 构造函数匹配的优先级冲突

st的两个构造函数中,st(const st&)可以接收所有三个候选转换的结果(const st&/st&&/const st&&都能绑定到const st&),而st(st&&)仅能接收operator st&&() &&的转换结果(非const右值引用无法绑定到const右值)。

按照C++标准,右值限定的转换运算符(operator st&&() &&)应该比const左值限定的转换运算符(operator const st&() const&)更匹配右值对象,理论上应该优先选择operator st&&() &&,进而调用移动构造函数。但实际出现差异的原因是:

  • MSVC行为:旧版本或特定编译设置下,可能错误地将const st&转换的优先级判定为更高,导致调用拷贝构造,属于编译器实现问题。
  • GCC/Clang报错:它们认为operator st&&() &&和operator const st&&() const&&同时匹配右值对象,且两者转换后对应构造函数的路径优先级相等,因此报歧义错误。

3. 补充说明的对应解释

  • 移除const & operator后,仅剩operator st&&() &&和operator const st&&() const&&,前者作为非const右值限定函数,对非const临时对象的匹配优先级更高,因此三款编译器都能选择移动构造路径。
  • 移除&& operator后,剩余const st&和const st&&转换,两者都只能匹配拷贝构造,GCC/MSVC认为const st&转换优先级更高,而Clang仍判定为歧义。
  • 移除两个右值限定转换后,仅剩const st&转换路径,无歧义,三款编译器均正常编译。

解决方案

删除冗余的operator const st&&() const&&——const右值引用的转换场景极少,保留operator st&() &、operator const st&() const&、operator st&&() &&即可避免歧义,让编译器正确选择移动构造路径。

内容的提问来源于stack exchange,提问作者ValueError

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:07:07