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

如何实现多条件继承?解决重复继承empty结构体编译错误

问题描述

我定义了一个带标志模板的build类型,通过激活的标志位继承对应类型,以此实现从多个子类构建大量配置的类。代码如下:

#include <type_traits>
#include <cstdint>

struct A { void a() {} };
struct B { void b() {} };
struct C { void c() {} };
struct D { void d() {} };

constexpr std::uint8_t FLAG_BIT_A = 0b1 << 0;
constexpr std::uint8_t FLAG_BIT_B = 0b1 << 1;
constexpr std::uint8_t FLAG_BIT_C = 0b1 << 2;
constexpr std::uint8_t FLAG_BIT_D = 0b1 << 3;

struct empty {};

template<std::uint8_t flags> 
using flag_a_type = std::conditional_t<(flags & FLAG_BIT_A), A, empty>;
template<std::uint8_t flags> 
using flag_b_type = std::conditional_t<(flags & FLAG_BIT_B), B, empty>;
template<std::uint8_t flags> 
using flag_c_type = std::conditional_t<(flags & FLAG_BIT_C), C, empty>;
template<std::uint8_t flags> 
using flag_d_type = std::conditional_t<(flags & FLAG_BIT_D), D, empty>;

template<std::uint8_t flags>
struct build : 
    flag_a_type<flags>, flag_b_type<flags>, flag_c_type<flags>, flag_d_type<flags> {

};

int main() {
    build<FLAG_BIT_A | FLAG_BIT_C> foo;
}

预期build<FLAG_BIT_A | FLAG_BIT_C>会继承A和C,但编译报错:

error C2500: 'build<5>': 'empty' is already a direct base class

需要在不定义4个不同empty结构体的前提下解决该问题。


解决方案1:给empty添加模板参数区分

把empty改成带模板参数的结构体,用不同参数生成不同空类型,避免重复直接基类的冲突:

#include <type_traits>
#include <cstdint>

struct A { void a() {} };
struct B { void b() {} };
struct C { void c() {} };
struct D { void d() {} };

constexpr std::uint8_t FLAG_BIT_A = 0b1 << 0;
constexpr std::uint8_t FLAG_BIT_B = 0b1 << 1;
constexpr std::uint8_t FLAG_BIT_C = 0b1 << 2;
constexpr std::uint8_t FLAG_BIT_D = 0b1 << 3;

template<int> struct empty {}; // 带模板参数的空结构体

template<std::uint8_t flags> 
using flag_a_type = std::conditional_t<(flags & FLAG_BIT_A), A, empty<0>>;
template<std::uint8_t flags> 
using flag_b_type = std::conditional_t<(flags & FLAG_BIT_B), B, empty<1>>;
template<std::uint8_t flags> 
using flag_c_type = std::conditional_t<(flags & FLAG_BIT_C), C, empty<2>>;
template<std::uint8_t flags> 
using flag_d_type = std::conditional_t<(flags & FLAG_BIT_D), D, empty<3>>;

template<std::uint8_t flags>
struct build : 
    flag_a_type<flags>, flag_b_type<flags>, flag_c_type<flags>, flag_d_type<flags> {

};

int main() {
    build<FLAG_BIT_A | FLAG_BIT_C> foo;
    foo.a();
    foo.c();
}

每个未激活标志对应的empty是不同的特化版本,编译器不会判定为重复直接基类。

解决方案2:递归链式继承

通过递归逐个处理标志位,用链式继承替代多重继承,避免同时继承多个empty:

#include <type_traits>
#include <cstdint>

struct A { void a() {} };
struct B { void b() {} };
struct C { void c() {} };
struct D { void d() {} };

constexpr std::uint8_t FLAG_BIT_A = 0b1 << 0;
constexpr std::uint8_t FLAG_BIT_B = 0b1 << 1;
constexpr std::uint8_t FLAG_BIT_C = 0b1 << 2;
constexpr std::uint8_t FLAG_BIT_D = 0b1 << 3;

struct empty {};

// 递归构建继承链
template<std::uint8_t flags, int bit = 0>
struct build_impl : std::conditional_t<
    (flags & (0b1 << bit)),
    std::conditional_t<bit == 0, A, 
    std::conditional_t<bit == 1, B, 
    std::conditional_t<bit == 2, C, D>>>,
    empty>,
    build_impl<flags, bit + 1> {};

// 终止递归的特化
template<std::uint8_t flags>
struct build_impl<flags, 4> : empty {};

template<std::uint8_t flags>
using build = build_impl<flags>;

int main() {
    build<FLAG_BIT_A | FLAG_BIT_C> foo;
    foo.a();
    foo.c();
}

链式继承中即使出现多个empty,也是间接继承,不会触发重复直接基类的错误。

解决方案3:C++17折叠表达式+元组展开

利用C++17的折叠表达式,只继承实际激活的目标类型,完全规避empty的重复问题:

#include <type_traits>
#include <cstdint>
#include <tuple>

struct A { void a() {} };
struct B { void b() {} };
struct C { void c() {} };
struct D { void d() {} };

constexpr std::uint8_t FLAG_BIT_A = 0b1 << 0;
constexpr std::uint8_t FLAG_BIT_B = 0b1 << 1;
constexpr std::uint8_t FLAG_BIT_C = 0b1 << 2;
constexpr std::uint8_t FLAG_BIT_D = 0b1 << 3;

// 辅助类,展开元组类型实现继承
template<typename... Ts>
struct inherit_from : Ts... {};

// 特化跳过void类型
template<typename... Ts>
struct inherit_from<void, Ts...> : inherit_from<Ts...> {};

template<>
struct inherit_from<void> {};

template<std::uint8_t flags>
struct build : inherit_from<
    std::conditional_t<(flags & FLAG_BIT_A), A, std::type_identity_t<void>>,
    std::conditional_t<(flags & FLAG_BIT_B), B, std::type_identity_t<void>>,
    std::conditional_t<(flags & FLAG_BIT_C), C, std::type_identity_t<void>>,
    std::conditional_t<(flags & FLAG_BIT_D), D, std::type_identity_t<void>>
> {};

int main() {
    build<FLAG_BIT_A | FLAG_BIT_C> foo;
    foo.a();
    foo.c();
}

用void作为未激活标志的占位符,通过inherit_from的特化跳过void,最终build只继承需要的目标类型。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:54:26