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

为何带有拷贝构造函数且删除移动构造的类无法自转换?

关于std::is_convertible与删除移动构造的类的问题

先看这段代码:

#include <type_traits>

struct OnlyCopyable {
    OnlyCopyable()  { }
    ~OnlyCopyable()  { }
    OnlyCopyable(const OnlyCopyable &src) { }
    OnlyCopyable& operator=(const OnlyCopyable &other) { return *this; }
    OnlyCopyable(OnlyCopyable &&other) = delete;
    OnlyCopyable& operator=(OnlyCopyable &&other) = delete;
};

static_assert(std::is_convertible_v<OnlyCopyable, OnlyCopyable>);

这段代码中的static_assert会失败,提示OnlyCopyable无法完成自转换;但如果把两个删除移动操作符的代码注释掉,断言就能正常通过。

原因分析

根据std::is_convertible的定义,它会检查虚构函数To test() { return std::declval<From>(); }是否合法。这里From和To都是OnlyCopyable,而std::declval<OnlyCopyable>()返回的是右值引用类型。

在C++的重载决议规则中,右值会优先匹配移动构造函数——哪怕这个移动构造函数是被显式delete的。因为删除的函数仍然会参与重载决议,当它被选中后,整个表达式就会变成非法,直接导致std::is_convertible_v<OnlyCopyable, OnlyCopyable>返回false。

而如果注释掉删除移动构造的代码,编译器不会生成可用的移动构造函数(因为类已经显式定义了拷贝构造,默认移动构造会被弃置),此时重载决议中没有移动构造这个候选,就会转而匹配拷贝构造函数。这时候虚构的test()函数是合法的,断言也就通过了。

简单来说:显式删除移动构造会让它进入重载候选列表,且优先级高于拷贝构造,选中后直接导致转换失败;不手动删除的话,移动构造不会出现在候选列表里,拷贝构造就能正常被选中,转换合法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:22:18