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

如何用C++参数包与模板函数区分满足concept的匿名结构体?

问题

我定义了一个C++20的concept myrequirement:

template<typename T>
concept myrequirement= requires(T s)
{
    { s.type() } -> std::same_as<uint8_t>;
};

enum MyType
{
    TYPE1,
    TYPE2,
    TYPE3,
};

使用者可以编写满足该约束的匿名结构体实例:

struct
{
    static constexpr uint8_t type() { return TYPE1;}
} foo;

struct
{
    static constexpr uint8_t type() { return TYPE2;}
} bar;

struct
{
    static constexpr uint8_t type() { return TYPE3;}
} baz;

我希望能通过类型值获取对应的实例,比如:

auto my_struct = get_instance<TYPE1>();

原本尝试用参数包实现,但编译失败:

template<uint8_t type, myrequirement... StructTypes> 
constexpr auto& get_instance_amongst(const StructTypes&... structs)
{
    // 如何实现?
}

template<uint8_t type>
constexpr auto& get_instance()
{
    return get_instance_amongst(foo, bar, baz);
}

请问有没有可行的实现方式?比如用折叠表达式?


可行实现方案

方法一:折叠表达式结合constexpr分支判断

利用C++20的constexpr条件判断和折叠表达式,逐个检查实例的type()是否匹配,找到后返回对应引用。同时添加静态断言处理无匹配项的情况:

#include <type_traits>
#include <cstdint>

// 保留原concept、枚举、实例定义...

// 辅助函数:检查单个实例是否匹配目标类型
template<uint8_t TargetType, myrequirement T>
constexpr const T* match_instance(const T& inst) {
    if constexpr (T::type() == TargetType) {
        return &inst;
    } else {
        return nullptr;
    }
}

template<uint8_t TargetType, myrequirement... Ts>
constexpr auto& get_instance_amongst(const Ts&... insts) {
    const auto* matched = nullptr;
    // 折叠表达式遍历所有实例,收集匹配的指针
    ( [&] {
        if (const auto* p = match_instance<TargetType>(insts); p != nullptr) {
            matched = p;
        }
    }(), ... );

    // 静态断言确保找到唯一匹配项
    static_assert(matched != nullptr, "No matching instance found for the given type");
    return *matched;
}

template<uint8_t TargetType>
constexpr auto& get_instance() {
    return get_instance_amongst<TargetType>(foo, bar, baz);
}

// 测试示例
int main() {
    constexpr auto& inst1 = get_instance<TYPE1>();
    static_assert(inst1.type() == TYPE1);

    constexpr auto& inst2 = get_instance<TYPE2>();
    static_assert(inst2.type() == TYPE2);
}

方法二:std::tuple存储+编译期索引查找

将所有实例存入std::tuple,通过编译期索引遍历查找匹配项:

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

// 保留原concept、枚举、实例定义...

// 编译期查找tuple中匹配的索引
template<uint8_t TargetType, typename Tuple, std::size_t... Idxs>
constexpr std::size_t find_match_idx(std::index_sequence<Idxs...>) {
    // 利用折叠表达式筛选匹配索引(假设唯一匹配)
    return ( (std::tuple_element_t<Idxs, Tuple>::type() == TargetType ? Idxs : 0) + ... );
}

template<uint8_t TargetType>
constexpr auto& get_instance() {
    constexpr auto instances = std::tie(foo, bar, baz);
    constexpr auto match_idx = find_match_idx<TargetType, decltype(instances)>(
        std::make_index_sequence<std::tuple_size_v<decltype(instances)>>{}
    );
    static_assert(std::tuple_element_t<match_idx, decltype(instances)>::type() == TargetType, "No matching instance");
    return std::get<match_idx>(instances);
}

核心说明

  1. 匿名结构体特性:每个匿名结构体都是独立类型,参数包StructTypes...会包含多个不同类型,折叠表达式可逐个处理。
  2. 编译期执行:所有匹配逻辑在编译阶段完成,无运行时开销。
  3. 唯一性保障:需确保每个TYPE值对应唯一实例,否则静态断言会触发编译错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:27:31