Create a comparative characteristic for template classes whose parameters are in a different order

UPDATE

My full featured TC implementation can be found on GitHub.

Question:

I am writing a unit conversion library. This is currently just a title and no dependencies that I would like to keep, if possible.

Compound units are defined in the library as simple unit patterns:

template<class... Units>
struct compound_unit { //...};

For simplicity, think of all types as pure tags, and therefore I can define a compound unit as:

struct meters {};
struct seconds {};

template<class Unit>
inverse { //... };

struct meters_per_second : 
    compound_unit<meters, inverse<seconds>> {};

where inverse is another pattern representing in this case 1 / second.

There are many constituent units that could be made, so I cannot make any assumptions about the number of variational arguments that it compound_unitwill take.

, - , , , -, :

struct meters_per_second : 
    compound_unit<meters, inverse<seconds>> {};

struct other_meters_per_second : 
    compound_unit<inverse<seconds>, meters> {};

magical_comparison_trait<meters_per_second, other_meters_per_second>::value; // == true

, ++ , , , ​​, , .

compound_unit, , , compound_unit ( , ). , - .

:

struct acceleration_1 : compound_unit<meters_per_second, inverse<second>> {};
struct acceleration_2 : compound_unit<meters, inverse<second>, inverse<second>> {};
+4
3

is_permutation - O (N ^ 2), , , , . , .

, :

template<class Meter, class Kilogram, class Second,
         class Ampere, class Kelvin, class Candela, class Mole>
struct unit {};

:

template<class, class> struct unit_multiply_impl;
template<class... Exps1, class... Exps2>
struct unit_multiply_impl<unit<Exps1...>, unit<Exps2...>> {
    using type = unit<std::ratio_add<Exps1, Exps2>...>;
};

template<class U1, class U2>
using unit_multiply = typename unit_multiply_impl<U1, U2>::type;

Inverse:

template<class U> struct inverse_impl;
template<class... Exps>
struct inverse_impl<unit<Exps...>> {
    using type = unit<std::ratio_multiply<Exps, std::ratio<-1>>...>;
};

template<class U> using inverse = typename inverse_impl<U>::type;

= :

template<class U, class... Us> struct compound_impl;
template<class U> struct compound_impl<U> { using type = U; };
template<class U1, class U2, class...Us>
struct compound_impl<U1, U2, Us...>
    :  compound_impl<unit_multiply<U1, U2>, Us...> {};

template<class U, class... Us>
using compound_unit = typename compound_impl<U, Us...>::type;

:

using std::ratio;
using meters = unit<ratio<1>, ratio<0>, ratio<0>, ratio<0>, ratio<0>, ratio<0>, ratio<0>>;
using seconds = unit<ratio<0>, ratio<0>, ratio<1>, ratio<0>, ratio<0>, ratio<0>, ratio<0>>;

using mps = compound_unit<meters, inverse<seconds>>;
using mps = compound_unit<inverse<seconds>, meters>;

using acc = compound_unit<mps, inverse<seconds>>;
using acc = compound_unit<meters, inverse<seconds>, inverse<seconds>>;

, compound_unit<mps, inverse<seconds>> compound_unit<meters, inverse<seconds>, inverse<seconds>> .

+3

, , .

:

<int, char> /*is equal to*/ <char, int>
<int, float, char> /*is equal to*/ <char, int, float>

, boost:: hana.

, compound_unit , .

#include <boost/hana.hpp>
using namespace boost;

template <typename... Ts>
struct compound_unit
{
    constexpr auto type_tuple()
    {
        return hana::tuple_t<Ts...>;
    }
};

template <typename TCU0, typename TCU1>
constexpr bool same_compound_unit(TCU0 cu0, TCU1 cu1)
{
    constexpr auto tt0(cu0.type_tuple());
    constexpr auto tt1(cu1.type_tuple());

    return (hana::is_subset(tt0, tt1) && hana::is_subset(tt1, tt0)) &&
           (hana::size(tt0) == hana::size(tt1));
}

int main()
{

    static_assert(same_compound_unit(compound_unit<int, float, char>{},
                      compound_unit<float, char, int>{}),
        "");

    static_assert(!same_compound_unit(compound_unit<int, float, char>{},
                      compound_unit<int, float, char, int>{}),
        "");

    static_assert(same_compound_unit(compound_unit<float, float, char>{},
                      compound_unit<char, float, char>{}),
        "");

    return 0;
}
+2

, , , , , .

:

#include <iostream>
#include <string>

#define METERS  1
#define SECONDS 3
#define INV     5

// ------- Start Unroll
// Unroll calculates the value of a compound type
template <typename... Type>
struct Unroll;

template <typename Type1, typename... Types> 
struct Unroll<Type1,Types...> {
    static constexpr int value = Type1::value * Unroll<Types...>::value;
};

template <typename Type>
struct Unroll<Type> {
    static constexpr int value = Type::value;
};

template <>
struct Unroll<> {
    static constexpr int value = 1;
};

// ---------- End Unroll

// Same definitions as in the question

template <typename... Units>
struct compound_unit {
    static constexpr int value = Unroll<Units...>::value;
};

struct meters {
    static constexpr int value = METERS;
};

struct seconds {
    static constexpr int value = SECONDS;
};

template <typename Unit>
struct inverse {
    // The -1 here can be anything, so long as is doesn't result in any of values which are defined at the top
    static constexpr int value = Unit::value * INV;
};

struct mps : compound_unit<meters, inverse<seconds>> {};
struct mps2 : compound_unit<inverse<seconds>, meters> {};

// Does the conversion using the Unroll struct to check that values are the same
template <typename T, typename V>
struct comparison_trait {
    static constexpr bool value = (T::value == V::value);
};

// Update for Bonus:

struct acc : compound_unit<mps, inverse<seconds>> {};
struct acc2 : compound_unit<meters, inverse<seconds>, inverse<seconds>> {};    

int main()
{
    bool check = comparison_trait<mps, mps2>::value;
    std::cout << "MPS check : " << check;

    bool check1 = comparison_trait<acc, acc2>::value;
    std::cout << "ACC check : " << check1;    
}

, "", #define , , , ID compound_type, Unroll struct.

. (1*4 == 2*2), , , , Jarod42. , .

, . .

, .

+1

Source: https://habr.com/ru/post/1626427/


All Articles