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

如何实现可检测派生类受保护构造的std::is_constructible等效方案?

等效于std::is_constructible的受保护构造检测方案

没问题,我来给你捋清楚怎么实现这个需求——要检测假设的派生类能否通过被测类的受保护构造函数完成构造,std::is_constructible确实派不上用场,因为它是从外部非友元、非派生的上下文判断构造可行性的,受保护成员对它来说属于不可访问范畴,会直接返回false,但实际上派生类是有权访问基类受保护构造的。

核心思路

我们可以创建一个临时的测试派生类,在这个派生类的上下文里尝试调用被测类的构造函数,利用SFINAE(替换失败不是错误)的特性来判断构造是否可行。因为测试类是被测类的派生类,所以天然拥有受保护成员的访问权限,这样就能准确模拟真实派生类的构造场景。

具体实现代码

#include <type_traits>
#include <utility>

namespace detail {
    // 定义一个继承自Base的测试类,用于模拟派生类上下文
    template <typename Base, typename... Args>
    struct test_derived : Base {
        // 如果Base(Args...)构造可行,这个重载会被选中,返回std::true_type
        static auto test(int) -> decltype(Base(std::declval<Args>()...), std::true_type{});
        // 构造不可行时,会 fallback 到这个重载,返回std::false_type
        static auto test(...) -> std::false_type;
    };
}

// 主模板,继承自测试类的test函数返回值类型
template <typename Base, typename... Args>
struct is_constructible_from_protected 
    : decltype(detail::test_derived<Base, Args...>::test(0)) {};

// 可选:添加变量模板,方便直接使用值
template <typename Base, typename... Args>
constexpr bool is_constructible_from_protected_v = is_constructible_from_protected<Base, Args...>::value;

代码工作原理

  1. detail::test_derived是被测类Base的派生类,所以它的成员函数test可以合法访问Base的受保护构造函数。
  2. 当我们调用test(0)时,编译器会优先尝试匹配第一个test重载:如果Base(std::declval<Args>()...)这个构造表达式合法,就会返回std::true_type;如果构造不合法(比如参数类型不匹配、构造函数不存在),SFINAE会让这个重载失效,转而匹配第二个返回std::false_type的重载。
  3. 最终is_constructible_from_protected的类型由decltype推导的返回值决定,完美模拟了派生类视角下的构造可行性。

使用示例

// 测试用的基类,包含受保护构造函数
class MyBase {
protected:
    MyBase(int) {}
    MyBase(double, bool) {}
public:
    MyBase() = default;
};

// 验证检测结果
static_assert(is_constructible_from_protected_v<MyBase>, "无参构造(公共)应该可行");
static_assert(is_constructible_from_protected_v<MyBase, int>, "int参数的受保护构造应该可行");
static_assert(is_constructible_from_protected_v<MyBase, double, bool>, "double+bool的受保护构造应该可行");
static_assert(!is_constructible_from_protected_v<MyBase, float>, "float参数的构造不存在,应该不可行");

扩展:检测特定派生类的构造可行性

如果你的需求是检测某个具体派生类能否调用基类的受保护构造,也可以调整实现,把派生类作为模板参数传入:

namespace detail {
    template <typename Derived, typename Base, typename... Args>
    auto test_specific_derived(int) -> decltype(
        // 在Derived的上下文里尝试构造Base(模拟Derived的初始化列表调用)
        static_cast<Derived*>(nullptr)->Base(std::declval<Args>()...), 
        std::true_type{}
    );
    template <typename Derived, typename Base, typename... Args>
    auto test_specific_derived(...) -> std::false_type;
}

template <typename Derived, typename Base, typename... Args>
struct is_constructible_from_protected_by 
    : std::enable_if_t<std::is_base_of_v<Base, Derived>, decltype(detail::test_specific_derived<Derived, Base, Args...>(0))> {};

template <typename Derived, typename Base, typename... Args>
constexpr bool is_constructible_from_protected_by_v = is_constructible_from_protected_by<Derived, Base, Args...>::value;

这个版本会先通过std::is_base_of确保Derived确实是Base的派生类,再检测构造可行性。

内容的提问来源于stack exchange,提问作者S. Paris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:49:11