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

如何用折叠表达式处理derived_unit的ratio集合与乘积计算

C++ 单位系统模板实现问题

给定以下类型定义:

template<Ratio r, Symbol s>
struct base_unit {
    using ratio = r;
    using symbol = s;
};

template <BaseUnit... baseUnits>
struct derived_unit {
    using units = std::tuple<baseUnits...>;
};

现有如下模板结构:

template <typename T>
struct Computations {
    using collection_ratios = /* */
    static constexpr ratios_product = /* */
};

其中T是derived_unit的特化类型(例如MetersPerSecond),需要完成以下实现:

  1. 利用折叠表达式将指定derived_unit的所有ratio存入std::array<T, N>类型(即collection_ratios);
  2. 利用折叠表达式计算derived_unit的units成员中所有元素的ratio乘积,并存储到ratios_product中。

补充定义如下:

template <typename T>
concept RatioV = (std::is_integral_v<T> || std::is_floating_point_v<T>)
    && !std::is_same_v<T, char>;


consteval double getFactor(double base, double exponent);

template <RatioV T = short, T Base = 10, T Exponent = 0>
struct ratio {
    static constexpr T base = Base;
    static constexpr T exponent = Exponent;
    static constexpr T value = getFactor(base, exponent);
};

consteval double getFactor(double base, double exponent) {
    double result = 1;
    for (int i = 0; i < exponent; i++)
        result *= base;
    return result;
}

using Yocto = ratio<short, 10, -24>;
using Zepto = ratio<short, 10, -21>;
using Atto = ratio<short, 10, -18>;
using Femto = ratio<short, 10, -15>;
using Pico = ratio<short, 10, -12>;
using Nano = ratio<short, 10, -9>;
using Micro = ratio<short, 10, -6>;
using Milli = ratio<short, 10, -3>;
using Centi = ratio<short, 10, -2>;
using Deci = ratio<short, 10, -1>;
using Root = ratio<short, 10, 0>;
using Deca = ratio<short, 10, 1>;
using Hecto = ratio<short, 10, 2>;
using Kilo = ratio<short, 10, 3>;
using Mega = ratio<short, 10, 6>;
using Giga = ratio<short, 10, 9>;
using Tera = ratio<short, 10, 12>;
using Peta = ratio<short, 10, 15>;
using Exa = ratio<short, 10, 18>;
using Zetta = ratio<short, 10, 21>;
using Yotta = ratio<short, 10, 24>;

实现方案

完整代码实现

#include <array>
#include <tuple>

// 补全BaseUnit概念,用于约束derived_unit的模板参数
template<typename U>
concept BaseUnit = requires(U u) {
    typename U::ratio;
    typename U::symbol;
};

template <typename T>
struct Computations;

// 针对derived_unit特化Computations模板
template <BaseUnit... Units>
struct Computations<derived_unit<Units...>> {
    // 1. 收集所有ratio到std::array
    using ratio_value_type = typename Units::ratio::value_type;
    static constexpr std::size_t unit_count = sizeof...(Units);
    using collection_ratios = std::array<ratio_value_type, unit_count>;

    // 编译期填充array的折叠表达式实现
    static constexpr collection_ratios ratios_array = []() constexpr {
        collection_ratios arr{};
        std::size_t idx = 0;
        ((arr[idx++] = Units::ratio::value), ...);
        return arr;
    }();

    // 2. 计算所有ratio的乘积
    static constexpr ratio_value_type ratios_product = []() constexpr {
        ratio_value_type result = 1;
        ((result *= Units::ratio::value), ...);
        return result;
    }();
};

实现说明

  1. 收集ratio到std::array:

    • 通过sizeof...(Units)获取单位数量,确定array的大小;
    • 使用constexpr lambda结合折叠表达式,遍历每个base_unit实例,将其ratio::value依次存入array对应索引位置。
  2. 计算ratio乘积:

    • 初始化乘积结果为1;
    • 利用折叠表达式对每个base_unit的ratio::value进行累乘,编译期计算出最终乘积。

测试示例

#include <iostream>

// 定义基础单位示例
struct MeterSymbol {};
using Meter = base_unit<Root, MeterSymbol>;

struct SecondSymbol {};
using Second = base_unit<Milli, SecondSymbol>;

// 导出单位:米每秒
using MetersPerSecond = derived_unit<Meter, Second>;

int main() {
    // 输出收集到的ratio数组:[1, 0.001]
    for (auto val : Computations<MetersPerSecond>::ratios_array) {
        std::cout << val << " ";
    }
    std::cout << "\n";

    // 输出乘积:0.001
    std::cout << Computations<MetersPerSecond>::ratios_product << "\n";
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:44:54