如何用折叠表达式处理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),需要完成以下实现:
- 利用折叠表达式将指定
derived_unit的所有ratio存入std::array<T, N>类型(即collection_ratios); - 利用折叠表达式计算
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; }(); };
实现说明
收集ratio到std::array:
- 通过
sizeof...(Units)获取单位数量,确定array的大小; - 使用constexpr lambda结合折叠表达式,遍历每个
base_unit实例,将其ratio::value依次存入array对应索引位置。
- 通过
计算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
相关产品推荐
相关产品推荐

