如何理解C++中move_constructible概念的实现逻辑?
C++
move_constructible概念实现逻辑解析 首先给出你提到的标准实现便于对照:
template<typename _Tp> concept move_constructible = constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>;
为什么用constructible_from<_Tp, _Tp>而不是constructible_from<_Tp, _Tp&&>
这两种写法语义完全等价,标准只是选择了更简洁的写法,原理如下:
std::constructible_from<T, Args...>的核心语义是:用Args...对应类型的右值作为参数,可显式构造出T类型对象,底层通过检测T(std::declval<Args>()...)表达式是否良构实现约束。std::declval<_Tp>()的返回值类型固定为_Tp&&(右值引用),因此constructible_from<_Tp, _Tp>实际检测的就是:能否用_Tp类型的右值构造_Tp对象,刚好匹配移动构造、或兼容右值的拷贝构造的调用场景。- 如果你写成
constructible_from<_Tp, _Tp&&>,std::declval<_Tp&&>()的返回值依然是_Tp&&,最终检测效果完全一致。
为什么需要看似多余的convertible_to<_Tp, _Tp>约束
“任何类型都可以转换为自身”的结论仅在转换构造函数非explicit时成立,这个约束的作用是校验隐式移动构造的合法性:
std::convertible_to<From, To>的核心语义是:From类型的右值可以隐式转换为To类型,底层通过检测类似To test() { return std::declval<From>(); }的隐式转换场景是否良构实现约束。- 如果一个类型的移动构造函数被声明为
explicit,_Tp obj = std::move(other);这类隐式构造场景就会编译失败,此时constructible_from<_Tp, _Tp>可能依然满足(显式构造合法),但convertible_to<_Tp, _Tp>会失败,刚好可以过滤掉这类不符合标准move_constructible语义的类型。 - 标准要求
move_constructible同时覆盖显式构造(如_Tp(std::move(obj)))和隐式构造(如_Tp obj = std::move(obj))两种场景,因此两个约束缺一不可。
你可以用以下代码验证上述逻辑:
#include <concepts> struct ExplicitMoveType { explicit ExplicitMoveType(ExplicitMoveType&&) = default; }; // 显式构造合法 static_assert(std::constructible_from<ExplicitMoveType, ExplicitMoveType>); // 隐式转换不合法 static_assert(!std::convertible_to<ExplicitMoveType, ExplicitMoveType>); // 不满足move_constructible约束 static_assert(!std::move_constructible<ExplicitMoveType>);
内容的提问来源于stack exchange,提问作者DeltA
相关产品推荐
相关产品推荐

