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

C++20中能否将概念作为模板参数定义通用约束概念?

在C++20中传递概念作为模板参数的方法

我已经在C++20中实现了两个约束范围元素的概念:

约束元素为浮点类型的RangeOfFloats

template <typename R>
concept RangeOfFloats = std::ranges::range<R> && std::floating_point<std::ranges::range_value_t<R>>;

static_assert(RangeOfFloats<std::span<float>>);
static_assert(RangeOfFloats<std::span<double>>);

约束元素为精确类型的RangeOfType

template <typename R, typename T>
concept RangeOfType = std::ranges::range<R> && std::is_same_v<std::ranges::range_value_t<R>, T>;

static_assert(RangeOfType<std::span<float>, float>);
static_assert(!RangeOfType<std::span<float>, double>);

现在我希望定义一个通用概念RangeOfThingsLike,能够接受另一个概念作为模板参数来约束范围元素,期望的语法如下:

template <typename R, template <typename> concept ElementConstraint>
concept RangeOfThingsLike = std::ranges::range<R> && ElementConstraint<std::ranges::range_value_t<R>>;

static_assert(RangeOfThingsLike<std::span<float>, std::floating_point>);

但上述语法是无效的。我尝试用类型特性替代,实现如下:

template <typename R, template <typename> typename ElementConstraint>
concept RangeOfThingsLike = std::ranges::range<R> && ElementConstraint<std::ranges::range_value_t<R>>::value;

static_assert(RangeOfThingsLike<std::span<float>, std::is_floating_point>);

但这种方式不够优雅。请问在C++20中是否存在将概念作为模板参数传递的有效方法?


解答

C++20不支持直接将概念作为模板模板参数(即template <typename> concept ElementConstraint这种写法不符合标准语法),但可以通过以下几种更优雅的替代方案实现类似需求:

方案1:将概念包装为constexpr模板变量

把目标概念包装成一个constexpr模板布尔变量,作为谓词传递给通用概念:

#include <ranges>
#include <concepts>
#include <span>

// 包装std::floating_point概念为constexpr模板变量
template <typename T>
constexpr bool is_floating_point = std::floating_point<T>;

// 通用范围概念,接受谓词模板
template <typename R, template <typename> typename Pred>
concept RangeOfThingsLike = std::ranges::range<R> && Pred<std::ranges::range_value_t<R>>;

// 使用示例
static_assert(RangeOfThingsLike<std::span<float>, is_floating_point>);
static_assert(RangeOfThingsLike<std::span<double>, is_floating_point>);

方案2:使用C++20的constexpr lambda作为非类型模板参数

利用C++20允许constexpr lambda作为非类型模板参数的特性,直接传递概念检查逻辑:

#include <ranges>
#include <concepts>
#include <span>

// 通用范围概念,接受一个可调用的constexpr谓词
template <typename R, auto Pred>
concept RangeOfThingsLike = std::ranges::range<R> && Pred.template operator()<std::ranges::range_value_t<R>>();

// 使用示例:传递检查std::floating_point的lambda
static_assert(RangeOfThingsLike<std::span<float>, []<typename T>() constexpr { return std::floating_point<T>; }>);

方案3:直接在使用时结合requires子句(简化场景)

如果不需要定义通用的RangeOfThingsLike概念,也可以直接在模板或函数中用requires子句组合范围约束和元素概念:

#include <ranges>
#include <concepts>
#include <span>

template <std::ranges::range R>
requires std::floating_point<std::ranges::range_value_t<R>>
void process_float_range(R&& range) {
    // 处理浮点类型范围
}

// 使用示例
void test() {
    std::span<float> floats{};
    process_float_range(floats); // 合法
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:07:45