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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 18:43:31