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

C++17:元组查找表未命中时如何触发编译期错误

编译期检查查找表匹配的实现方案

需求背景

现有一个基于元组的查找表,包含多种Entry类型,每个Entry通过fits函数判断是否匹配目标值,匹配则返回对应的setting值。需要实现当待搜索值不在查找表中时触发编译期错误的功能,但现有查找函数无法满足该需求。

现有查找函数

template <typename TLookup, typename TValueToSearch, typename TSetting>
constexpr auto lookupNeededSetting(const TValueToSearch &valueToSearch)
{
  TSetting setting = {};
  typename TLookup::Type const table = typename TLookup::Type{};

  std::apply(
      [&valueToSearch, &setting](const auto &...entry) {
        // 遍历表中每个条目
        return (((entry.fits(valueToSearch)) ? setting = entry.value() : false) || ...);
      },
      table);

  return setting;
}

查找表定义

template <typename... TEntries>
struct LookupTable
{
  using Type = std::tuple<TEntries...>; ///< 表示条目元组的类型
};

尝试的实现及错误

尝试通过模板类结合constexpr逻辑实现编译期检查,但编译器报错tempSetting不是常量:

template <typename TLookup, typename TValueToSearch, typename TSetting, auto VValueToSearch>
constexpr bool lookupNeededSetting2(TSetting& setting) {
    bool found = false;
    typename TLookup::Type const table = typename TLookup::Type{};

    std::apply(
        [&found, &setting](const auto&... entry) {
            // 遍历表中每个条目
            ((entry.fits(VValueToSearch) ? (setting = entry.value(), found = true) : false) || ...);
        },
        table);

    return found;
}

template <typename TLookup, typename TValueToSearch, typename TSetting, auto VValueToSearch>
class Lookup {
public:
    static constexpr TSetting setting = [] {
        TSetting tempSetting{};
        constexpr bool found = lookupNeededSetting2<TLookup, TValueToSearch, TSetting, VValueToSearch>(tempSetting);
        static_assert(found, "The given VValueToSearch was not found in the lookup table.");
        return tempSetting;
    }();

    static constexpr auto value = setting;
};

错误原因

lambda中的tempSetting是自动变量,并非常量表达式。lookupNeededSetting2调用时修改了该变量,导致整个函数调用无法成为常量表达式,因此无法用constexpr bool接收返回值,也无法满足static_assert对常量表达式的要求。

解决方案

将检查和查找逻辑拆分为两个独立的constexpr函数,确保所有操作在编译期完成,避免依赖运行时变量修改:

1. 编译期检查匹配条目是否存在

template <typename TLookup, auto VValueToSearch>
constexpr bool hasMatchingEntry() {
    constexpr auto table = typename TLookup::Type{};
    return std::apply([](const auto&... entry) {
        // 折叠表达式判断是否存在匹配条目
        return (entry.fits(VValueToSearch) || ...);
    }, table);
}

2. 编译期获取匹配的Setting值

template <typename TLookup, typename TSetting, auto VValueToSearch>
constexpr TSetting getMatchingSetting() {
    constexpr auto table = typename TLookup::Type{};
    TSetting setting{};
    // 已通过hasMatchingEntry确认存在匹配,因此必然能找到对应条目
    std::apply([&](const auto&... entry) {
        ((entry.fits(VValueToSearch) ? (setting = entry.value()) : void()), ...);
    }, table);
    return setting;
}

3. 最终Lookup模板类

template <typename TLookup, typename TSetting, auto VValueToSearch>
class Lookup {
public:
    // 编译期断言:必须存在匹配条目
    static_assert(hasMatchingEntry<TLookup, VValueToSearch>(), 
                  "The given value was not found in the lookup table.");
    
    // 编译期初始化匹配的Setting值
    static constexpr TSetting value = getMatchingSetting<TLookup, TSetting, VValueToSearch>();
};

关键注意事项

  • Entry类的fits和value函数必须是constexpr,才能在编译期被调用。
  • 拆分逻辑后,hasMatchingEntry返回纯常量表达式,可直接用于static_assert触发编译期错误;getMatchingSetting在确认存在匹配的前提下,通过编译期遍历赋值,确保返回值是常量表达式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:57:51