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

如何创建带参数包的递归C++ concept,使匹配越多重载优先级越高

实现带参数包的C++ Concept并让匹配项越多重载优先级越高

问题描述

能否定义一个带类型参数包的C++ concept,实现“匹配的参数项越多,对应的重载函数优先级越高”的效果?具体来说,针对以下给定类型:

template <typename U, typename V>
struct MyType {};

struct TypeA {};
struct TypeB {};

我们希望定义WithMyType concept,支持如下重载调用逻辑:

void foo(WithMyType auto);               // (1) 最宽松匹配
void foo(WithMyType<TypeA> auto);        // (2) 匹配包含TypeA的MyType
void foo(WithMyType<TypeA, TypeB> auto); // (3) 同时包含TypeA和TypeB的MyType,优先级最高

int main() {
  auto aa = MyType<TypeA, TypeA>();
  auto ab = MyType<TypeA, TypeB>();
  auto bb = MyType<TypeB, TypeB>();

  foo(aa); // 匹配(1)(2),调用优先级更高的(2)
  foo(ab); // 匹配(1)(2)(3),调用优先级最高的(3)
  foo(bb); // 仅匹配(1),调用(1)
}

解决方案

可以实现该需求,核心是利用C++20 concept的约束强度规则:约束条件越具体、数量越多,对应的重载优先级越高。我们通过递归式的concept定义,让参数包长度越长,约束越严格。

完整实现代码

#include <type_traits>
#include <cstdio>

template <typename U, typename V>
struct MyType {};

struct TypeA {};
struct TypeB {};

// 辅助判断:类型X是否是U或V中的一个
template <typename X, typename U, typename V>
constexpr bool is_one_of = std::is_same_v<X, U> || std::is_same_v<X, V>;

// 基础版本:无额外参数,仅检查T是否是MyType实例
template <typename T>
concept WithMyType = requires {
  // 通过模板推导验证T是MyType<U,V>的实例
  []<typename U, typename V>(MyType<U, V>) {}((T{}));
};

// 递归版本:检查第一个参数是否存在于MyType的类型中,同时剩余参数满足WithMyType
template <typename T, typename First, typename... Rest>
concept WithMyType<T, First, Rest...> = 
  WithMyType<T> && 
  requires(T t) {
    // 提取T的MyType参数,验证First是其中之一
    []<typename U, typename V>(MyType<U, V>) {
      static_assert(is_one_of<First, U, V>);
    }(t);
  } && 
  WithMyType<T, Rest...>;

// 重载函数
void foo(WithMyType auto) {               // (1)
  printf("调用重载(1)\n");
}

void foo(WithMyType<TypeA> auto) {        // (2)
  printf("调用重载(2)\n");
}

void foo(WithMyType<TypeA, TypeB> auto) { // (3)
  printf("调用重载(3)\n");
}

int main() {
  auto aa = MyType<TypeA, TypeA>();
  auto ab = MyType<TypeA, TypeB>();
  auto bb = MyType<TypeB, TypeB>();

  foo(aa); // 输出:调用重载(2)
  foo(ab); // 输出:调用重载(3)
  foo(bb); // 输出:调用重载(1)
}

工作原理

  1. 基础约束WithMyType<T>:仅验证T是MyType<U,V>的实例,是最宽松的约束。
  2. 递归约束WithMyType<T, First, Rest...>:
    • 首先满足基础约束WithMyType<T>;
    • 然后检查First是否是MyType的两个模板参数之一;
    • 最后递归验证剩余的Rest参数也满足约束。
  3. 重载决议优先级:由于递归版本的约束包含更多检查条件,编译器会认为其约束更严格,因此匹配时会优先选择参数包长度更长的重载版本。

验证结果

编译运行上述代码,输出符合预期:

调用重载(2)
调用重载(3)
调用重载(1)

内容的提问来源于stack exchange,提问作者Michael Schlottke-Lakemper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:33:26