C++中如何忽略模板参数判断类型是否属于同一维度
问题:在C++中忽略模板参数判断类型所属维度
在C++中,我需要判断两种类型是否属于同一维度(如mass),以便对同维度类型执行转换,不同维度则禁止操作。现有代码结构如下:
首先是维度基类与具体维度模板:
template<Ratio prefix, Symbol S> class base_magnitude {}; /* ... 用于表示比率和符号的其他类型 */ template <Ratio R, Symbol S> class mass: public base_magnitude<R, S> {}; template <Ratio R, Symbol S> class length: public base_magnitude<R, S> {};
然后是具体的单位类型定义:
struct Kilogram: public mass<Kilo, kg> { using dimension = mass; using ratio = Kilo; }; struct Hectogram: public mass<Hecto, hg> { using dimension = mass; using ratio = Hecto; }; struct Kilometer: public length<Kilo, km> { using dimension = length; using ratio = Kilo; };
我尝试用concept来检查同维度,但遇到问题:
template <typename T> concept Magnitude = requires { typename T::dimension; typename T::ratio; }; template <typename T, typename R> concept SameMagnitude = requires { requires Magnitude<T> && Magnitude<R>; requires std::is_same_v<typename T::dimension, typename R::dimension>; };
实际中,using dimension = mass会被解析为实例化后的具体类型:
Kilogram的dimension是mass<Kilo, kg>Hectogram的dimension是mass<Hecto, hg>
因此std::is_same_v无法判定两者属于同一维度。我试过SFINAE和标签分发方案,但标签分发需要额外继承类型,会增加公共API复杂度,希望找到更简洁的实现方式。
解决方案:提取模板的原始类型进行比较
核心思路是编写一个模板元函数,从实例化后的模板类中提取其原始模板类型(即去掉模板参数后的模板本身),然后比较两个类型的原始模板是否一致。
1. 实现模板提取元函数
根据模板参数的类型(类型参数/非类型参数),选择对应的实现:
情况1:模板参数为类型参数
template<typename T> struct get_template; // 偏特化:匹配任意带类型参数的模板实例 template<template<typename...> class Template, typename... Args> struct get_template<Template<Args...>> { using type = Template; }; // 便捷别名 template<typename T> using get_template_t = typename get_template<T>::type;
情况2:模板参数包含非类型参数(如你的Ratio/Symbol)
C++17及以后支持用auto作为非类型模板参数的占位符,因此可以调整为:
template<typename T> struct get_template; // 偏特化:匹配任意带非类型参数的模板实例 template<template<auto...> class Template, auto... Args> struct get_template<Template<Args...>> { using type = Template; }; template<typename T> using get_template_t = typename get_template<T>::type;
2. 修改SameMagnitude Concept
使用提取的原始模板类型进行比较:
template <typename T> concept Magnitude = requires { typename T::dimension; typename T::ratio; }; template <typename T, typename R> concept SameMagnitude = requires { requires Magnitude<T> && Magnitude<R>; // 比较两个维度的原始模板是否相同 requires std::is_same_v<get_template_t<typename T::dimension>, get_template_t<typename R::dimension>>; };
效果验证
SameMagnitude<Kilogram, Hectogram>:两者的dimension提取后都是mass模板,判定为同一维度SameMagnitude<Kilogram, Kilometer>:前者提取为mass,后者为length,判定为不同维度
该方案无需修改现有维度类或单位类的定义,不会增加公共API复杂度,完全符合需求。
内容的提问来源于stack exchange,提问作者Alex Vergara
相关产品推荐
相关产品推荐

