c++ 比较模板化类型而不考虑模板参数

knpiaxh1  于 2023-02-26  发布在  其他
关注(0)|答案(2)|浏览(207)

C++中是否可以比较两个类型而不考虑模板参数?

struct Kilogram: public mass<Kilo, kg> {
    using dimension = mass;
    using ratio = Kilo;
};
struct Hectogram: public mass<Kilo, kg> {
    using dimension = mass;
    using ratio = Hecto;
};

所以,在一个概念中,我想检查两个类型是否属于同一个维度mass,这样我就可以在与维度相关的类型中执行转换,但在不同的维度上就不行了。

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>;
    };

我探索了std::true_typestd::false_type的SFINAE选项,tag dispathching,但它们对我来说还不够,因为标签调度会让我从另一个类型继承,比如mass_dimension,所以我的公共API开始变得越来越复杂,我希望尽可能地让事情变得简单。
如何比较两个类别是否具有相同的质量维度,但不考虑质量类型的模板参数?
编辑:其中质量:

template<Ratio prefix, Symbol S>
class base_magnitude {}; /* ... more types to represent ratios and symbols */

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 Kilometer: public length<Kilo, km> {
    using dimension = length;
    using ratio = Kilo;
};

但是,如前所述,对于共享相同维度的类型,我仍然希望在概念中生成true,如前一个示例所示,KilogramHectogram必须生成true,因为它们都是mass的子类型。
我的问题是using dimension = mass实际上是:

Kilogram -> using dimension = mass<Kilo, kg>...
Hectogram -> using dimension = mass<Hecto, hg>...

因此,这个概念应该验证两者具有相同的维度mass,但是由于我的类型接收模板参数,因此它们不是相同的类型。

nwlqm0z1

nwlqm0z11#

我没有编译你的代码,但是我想我理解它的作用。你可以使用部分特化来检查两个类型是否是同一个模板的示例化。当成员别名dimension可以用于比较时,你代码中的继承就不那么重要了(这要简单得多)。没有概念,只有基本的模板东西,但我想这个想法可以翻译成更现代的C++,而不需要太多的努力:

#include <iostream>
#include <type_traits>

template <int x>
struct foo {};

struct A { using dimension = int; };
struct B { using dimension = foo<0>; };
struct C { using dimension = foo<1>; };

template <typename S,typename T>
struct same_dimension_template_impl : std::false_type {};

template <template <int> typename X,int a,int b>
struct same_dimension_template_impl<X<a>,X<b>> : std::true_type {};

template <typename A,typename B>
constexpr bool same_dimension_template_v = same_dimension_template_impl< typename A::dimension, typename B::dimension>::value;

int main() {
    std::cout << same_dimension_template_v<A,B>;
    std::cout << same_dimension_template_v<A,C>;
    std::cout << same_dimension_template_v<B,C>;
}

Live Demo

rekjcdws

rekjcdws2#

你可以创建一个泛型trait来检查两个类型是否基于同一个模板:

template<class T, class U>
struct same_template {
    static auto test(...) -> std::false_type;

    template<template<class...> class C, class... R1s, class... R2s>
    static auto test(C<R1s...>, C<R2s...>) -> std::true_type;

    static constexpr bool value = decltype(test(std::declval<T>(),
                                                std::declval<U>()))::value;
};

template<class T, class U>
inline constexpr bool same_template_v = same_template<T, U>::value;

template<class T, class U>
concept SameTemplate = same_template_v<T, U>;

示例:

template<class T, class U>
requires SameTemplate<T, U>
void Foo(T&&, U&&) {

}

int main() {
    //Foo(Kilometer{}, Kilogram{}); // Error
    Foo(Gram{}, Kilogram{});        // Ok (after you've added `Gram`)
}

Demo

相关问题