如何让C++构造函数仅在特定条件下参与重载决议?
模板类移动构造函数的重载决议控制方案
要让Test<T>的移动构造函数仅在T为void或具备移动构造能力时参与重载决议,不能靠将其定义为deleted(因为deleted函数仍会参与决议,只是选中后触发编译错误),得用SFINAE机制或C++20的requires子句来实现精准过滤。
方案一:C++11及以上兼容的SFINAE写法
通过给移动构造函数添加模板参数,结合std::enable_if来限定参与决议的条件:
#include <type_traits> template <typename T> class Test { public: Test() = default; // 移动构造函数:仅当T是void或T可移动构造时生效 template <typename U = T, typename = std::enable_if_t< std::is_void_v<U> || std::is_move_constructible_v<U> >> Test(Test&&) noexcept { // 自定义移动构造逻辑 } // 拷贝构造函数(作为重载候选) Test(const Test&) = default; };
这里利用模板参数U的默认值绑定T,当std::enable_if_t的条件不满足时,该移动构造函数会被SFINAE规则剔除,完全不进入重载决议候选集。
方案二:C++20及以上的requires写法
如果使用C++20或更高版本,requires子句能更直观地实现条件限定:
#include <type_traits> template <typename T> class Test { public: Test() = default; // 移动构造函数:直接用requires限定参与决议的条件 Test(Test&&) noexcept requires (std::is_void_v<T> || std::is_move_constructible_v<T>) { // 自定义移动构造逻辑 } Test(const Test&) = default; };
requires子句直接附加在函数声明后,条件不满足时该函数不会被纳入重载候选列表,逻辑更清晰。
关键说明
- 为什么不用
deleted?因为Test(Test&&) = delete;只是标记该函数不可用,但它依然会出现在重载决议的候选池中。当编译器匹配到这个函数时,会直接抛出编译错误,而非跳过它选择其他重载(比如拷贝构造)。 - 针对
T=void的场景:由于void没有实例,移动构造函数内部无需处理T的移动操作,只需保证函数能正常参与决议即可。
内容的提问来源于stack exchange,提问作者LunarEclipse
相关产品推荐
相关产品推荐

