我正在實作編譯時的單位系統,我能夠將不同的單位相乘,例如:
我正在實作編譯時的單位系統。
Scalar<int, M_>{2}。*Scalar<int, M_>{2} ==Scalar<int, M_, M>{4};
我還希望能這樣做:
我希望能這樣做:
Scalar<int, M_, M_>{4}. / Scalar<int, M_>{2} == Scalar<int, M_>{2};
而我認為一個好的開始是將類似的單位歸入一個template< typename T, int P> struct UnitPower型別,以便
Scalar<int, UnitPower<M_, 1>>{2}。*Scalar<int, UnitPower<M_, 1>>{2} == Scalar< int, UnitPower<M_, 2> >{4};
而且
Scalar<int, UnitPower<M_, 2>>{4}。/ Scalar<int, UnitPower<M_, 1>>{2} == Scalar< int, UnitPower<M_, 1> >{2};
這將在一個更普遍的情況下派上用場:
Scalar<double, UnitPower< M_, 1> , UnitPower<S_, -2>, UnitPower<G_, 1>>{70}. / Scalar<double, UnitPower<M_, 1>, UnitPower<S_, -1>>{10} == Scalar< double, UnitPower<S_, -1>, UnitPower<G_, 1> >{7}.
我還需要使運算子與這些UnitPowers的順序無關。
到目前為止,代碼如下:
struct M_。
struct S_;
struct Mps_;
template<typename T, int P>
struct UnitPower {};
template<typename T, int P, typename。R>
struct group_units {
//static constexpr type = ?
};
template <typename T, class... C>
struct Scalar
{
protected:
T值。
public:
constexpr explicit Scalar(const T value) : value(value) {}。
template<typename U>
constexpr auto operator<=>(const Scalar<U, C...> rhs) {
return value <=> static_cast<U>(rhs.value)。
}
template<typename U>
constexpr bool operator==(const Scalar<U, C. ...> rhs) const { return value == static_cast<T> (rhs); }
template<typename U, typename.... D>
constexpr Scalar<std::common_type_t<T, U> , C..., D... > operator/(const Scalar<U, D...> rhs) const{
using V = std::common_type_t<T, U> 。
return Scalar<V, C..., D...>{static_cast<V>(value) / static_cast<V>(rhs) };
}
template<typename U, typename... D>
constexpr Scalar<std::common_type_t<T, U> , C..., D... > operator*(constScalar<U, D...> rhs) const {
using V = std::common_type_t<T, U> 。
return Scalar<V, C..., D...>{static_cast<V>(value) * static_cast<V>(rhs) };
}
template<typename U>
constexpr std::common_type_t<T, U> operator/(const Scalar< U, C. ...> rhs) const {
using V = std::common_type_t<T, U> 。
return static_cast<V>(value) / static_cast<V>(rhs) 。
}
template<typename U>
constexpr Scalar<std::common_type_t<T, U>, C. 。 > operator/(const U rhs) const {
using V = std::common_type_t<T, U> 。
return Scalar<V, C...>{static_cast<V>(value) / static_cast<V>(rhs) };
}
constexpr explicit operator T() const{ return value; }
template<typename U>
constexpr explicit operator U() const{ return static_cast< U>(value); }
};
template<typename T>
struct Meters : Scalar<T, M_> { using Scalar<T, M_> :Scalar; };
template<typename T>
struct Seconds : Scalar<T, S_> { using Scalar<T, S_> :Scalar; };
正如你所看到的,除法運算子目前只定義了相同的單位(以相同的順序),并且只回傳一個數字(在這種情況下是正確的回傳型別),或者只取一個數字,回傳Scalar而不修改單位,這也是正確的行為。
乘法運算子只是追加了單位,我需要它首先對它們進行分組。
我已經添加了
template<int P, typename T>
struct UnitPower {};
template<int P, typename T, typename。R>。
struct group_units {
//static constexpr type = ?
};
一部分,但我真的不知道該如何去做。
我也不知道該如何去做。
我也不確定如何使操作者的單元順序不受影響。
在學習了如何對乘法運算子進行單位分組之后,除法運算子在單位方面將與乘法運算子類似--只是在右側使用負數。
因此,我的問題有兩個方面:
UnitPower<U, int>結構,并省略功率為0的單位?(如果省略了所有的UnitPowers,則將Scalar衰減為基礎值型別)。uj5u.com熱心網友回復:
相當具有挑戰性...... 盡管我只做了一些基本的測驗,下面的代碼似乎是有效的,至少它應該給你一些如何解決這個問題的提示。還有相當多的潛力來美化代碼(盡管在最近的編輯中變得更少),我的模板的命名肯定是其他的,但不是最佳的 - 但我把這些留給你來解決... 作為一個小的補償部門,我們也已經提供了。
這個想法總是基于同一個基本原則:我們需要遞回到模板引數中來進行我們需要的型別更改。牢記這一點,應該可以理解下面的代碼。如果還有問題,請隨時留言。
template <typename Unit, int>
struct UnitPower { };
template <typename T, typename ...。單位>。
struct Scalar
{
T值。
};
template <typename ... 單位>。
struct concat。
template <typename ... 單位>。
using concat_t = typename concat<Units...> :type。
template <typename U, typename ...。單位>。
struct concat<U, std::tuple<Units...>>。
{
using type = std::tuple<U, Units...>。
};
template <typename ... UnitsX, typename ...。UnitsY>
struct concat<std::tuple<UnitsX...> , std::tuple<UnitsY...>>。
{
using type = std::tuple<UnitsX..., UnitsY...>。
};
template <typename ... 單位>。
struct powers。
template <typename ... 單位>。
using powers_t = typename powers<Units...> :type。
template <>
struct powers<>
{
using type = std::tuple<> 。
};
template <typename U, typename ...。單位>。
struct powers<U, Units...>
{
using type = concat_t<UnitPower<U, 1> , powers_t<Units...>。
};
template <typename U, int N, typename ... 單位>。
struct powers<UnitPower<U, N> , Units...>
{
using type = concat_t<UnitPower<U, N>, powers_t<Units...> >。
};
template <typename ... 單位>。
struct count。
template <typename ... 單位>。
using count_t = typename count<Units...> :type;
template <typename U, int P>
struct count<UnitPower<U, P> >
{
using type = UnitPower<U, P> 。
};
template <typename U, int PX, int PY, typename ...。單位>。
struct count<UnitPower<U, PX> , UnitPower<U, PY> , Units...>
{
using type = count_t<UnitPower<U, PX PY>, Units...> 。
};
template < typename UX, int PX, typename UY, int PY, typename 。 .. 單位>。
struct count<UnitPower<UX, PX> , UnitPower<UY, PY> , Units...>
{
using type = count_t<UnitPower<UX, PX>, Units...> 。
};
template < typename ... 單位>。
struct count<std::tuple<Units...>>。
{
using type = count_t<Units...>。
};
template <typename ... 單位>。
struct remain。
template <typename ... 單位>。
using remain_t = typename remain<Units...> :type。
template <typename U, int P>
struct remain<UnitPower<U, P> >
{
using type = std::tuple<>。
};
template <typename U, int PX, int PY, typename ...。單位>。
struct remain<UnitPower<U, PX> , UnitPower<U, PY> , Units...>
{
using type = remain_t<UnitPower<U, PX>, Units...> 。
};
template < typename UX, int PX, typename UY, int PY, typename . .. 單位>。
struct remain<UnitPower<UX, PX> , UnitPower<UY, PY> , Units...>
{
using type = concat_t<
UnitPower<UY, PY>。
remain_t< UnitPower<UX, PX>, Units...>
>。
};
template < typename ... 單位>。
struct remain<std::tuple<Units...>>。
{
using type = remain_t<Units...> 。
};
template <typename ... 單位>。
struct combine。
template <typename ... 單位>。
using combine_t = typename combine<Units...> :type。
template <>
struct combine<>
{
using type = std::tuple<> 。
};
template <typename U, int P>
struct combine<UnitPower<U, P> >
{
using type = std::tuple<UnitPower<U, P>> 。
};
template <typename U, int P, typename ...。單位>。
struct combine<UnitPower<U, P> , Units...>
{
using type = concat_t<
count_t<UnitPower<U, P>, Units...> 。
combine_t<remain_t<UnitPower<U, P>, Units...>>。
>。
};
template <typename ... 單位>。
struct combine<std::tuple<Units...>>。
{
using type = combine_t<Units...>。
};
template <typename ... 單位>。
struct normalize。
template <typename ... 單位>。
using normalize_t = typename normalize<Units...> ::type。
template <>
struct normalize<>
{
using type = std::tuple<> 。
};
template <typename U, typename ...。單位>。
struct normalize<UnitPower<U, 0>, Units...>
{
using type = normalize_t<Units...>。
};
template <typename U, typename ... 單位>。
struct normalize<UnitPower<U, 1>, Units...>
{
using type = concat_t<U, normalize_t< Units...>。
};
template <typename U, int N, typename ... 單位>。
struct normalize<UnitPower<U, N> , Units...>
{
using type = concat_t<UnitPower<U, N>, normalize_t<Units...> > 。
};
template <typename ... 單位>。
struct normalize<std::tuple<Units...>>。
{
using type = normalize_t<Units...>。
};
template <typename T, typename ... 單位>。
struct scalar。
template <typename ... 單位>。
using scalar_t = typename scalar<Units...> :type。
template <typename T, typename ... 單位>。
struct scalar<T, std::tuple<Units...>>。
{
using type = Scalar<T, Units...> 。
};
template <typename ... T>
struct multiply。
template <typename ... T>
using multiply_t = typename multiply<T...> :type。
template <typename TX, typename TY, typename ... UnitsX, typename ...。UnitsY>
struct multiply<TX, TY, std::tuple<UnitsX...> , std::tuple<UnitsY...>>
{
using type = scalar_t<
decltype(std::declval<TX>() * std::declval<TY>() 。)
normalize_t<combine_t< concat_t<
powers_t<UnitsX...>, powers_t<UnitsY...>。
>>>。
>。
};
template <typenameTX, typenameTY, typename ... UnitsX, typename ...。UnitsY>
auto operator*(Scalar<TX, UnitsX...> x, Scalar< TY, UnitsY...> y)
-> multiply_t<TX, TY, std::tuple<UnitsX...> , std::tuple<UnitsY...>>
{
return {x.value * y.value};
}
template <typename ...。單位>。
struct negate。
template <typename ... 單位>。
using negate_t = typename negate<Units...> :type;
template <>
struct negate<>
{
using type = std::tuple<> 。
};
template <typename U, int N, typename ...。單位>。
struct negate<UnitPower<U, N>, Units... >
{
using type = concat_t<UnitPower<U, -N>, negate_t<Units...>> 。
};
template <typename ... 單位>。
struct negate<std::tuple<Units...>>。
{
using type = negate_t<Units...> 。
};
template <typename ... T>
struct divide。
template <typename ... T>
using divide_t = typename divide<T...> :type。
template <typename TX, typename TY, typename ... UnitsX, typename ...。UnitsY>
struct divide<TX, TY, std::tuple<UnitsX...> , std::tuple<UnitsY...>>
{
using type = scalar_t<
decltype(std::declval<TX>() / std::declval<TY>() ) 。
normalize_t<combine_t< concat_t<
powers_t<UnitsX...>, negate_t<powers_t<UnitsY...> >
>>>。
>。
};
template <typenameTX, typenameTY, typename ... UnitsX, typename ...。UnitsY>
auto operator/(Scalar<TX, UnitsX...> x, Scalar< TY, UnitsY...> y)
-> divide_t<TX, TY, std::tuple<UnitsX...> , std::tuple<UnitsY...>>
{
return {x.value / y.value};
}
uj5u.com熱心網友回復:
這是我想出來的。
這是我想出來的。
#include <tuple>
#include <type_traits>
template <typename T, typename Tuple>
struct remove_from_tuple;
template <typename T, typename Tuple>
using remove_from_tuple_t = typename remove_from_tuple<T, Tuple> ::type;
template <typename T, typename...。ElemT>
struct remove_from_tuple<T, std::tuple<ElemT...>> {
using type = decltype(std::tuple_cat(std::declval<
std::conditional_t<std::is_same_v<T, ElemT>, std::tuple<>, std::tuple<elemT>>
>()...))。
static constexpr std::size_t removed =
sizeof...(ElemT) - std::tuple_size<type> ::value。
};
template <class Tuple1, class Tuple2>
struct is_tuple_permutation : std::false_type {};
template <class Tuple1, class Tuple2>
constexpr bool is_tuple_permutation_v = is_tuple_permutation<Tuple1, Tuple2> ::value。
template<>
struct is_tuple_permutation<std::tuple<>, std::tuple<>
: public std::true_type {};
template <typename T, typename.... List1, typename Tuple2>
struct is_tuple_permutation<std::tuple<T, List1...> , Tuple2> {
private:
using remove1_t = remove_from_tuple<T, std::tuple<List1...>>。
使用 remove2_t = remove_from_tuple<T, Tuple2>。
public:
static constexpr bool value =
1 remove1_t::removed == remove2_t::removed&&
is_tuple_permutation_v<typename remove1_t::type, typename remove2_t::type>。
};
結構 M_。
結構 S_;
struct KG_;
template <class Tag, int P>
struct UnitPower {};
//Trait: UnitPower<Tag0, P0>, UnitPower<Tag1, P1>, ...。-> Tag0
template <class。單位>。
struct first_tag。
template <class... 單位>。
using first_tag_t = typename first_tag<Units...>:type。
template <class Tag0, int P0, class ... 單位>。
struct first_tag<UnitPower<Tag0, P0> , Units...> {
using type = Tag0;
};
// 特質。所有具有匹配標簽的UnitPower在單位中的權力總和......;
//將所有具有不同Tag的Unit...放入元組余數中。
template <class Tag,class... 單位>。
struct collect_unit。
template <class Tag,class... 單位>。
constexpr int collect_unit_power = collect_unit<Tag, Units...>:power。
template <class Tag,class... 單位>。
using collect_unit_remainder_t = typename collect_unit<Tag, Units...>::remainder。
template <class Tag>
struct collect_unit< Tag> {
static constexpr int power = 0;
using remainder = std::tuple<> 。
};
template <class Tag, int P0, class... 單位>。
struct collect_unit<Tag, UnitPower<Tag, P0>, Units...> {
static constexpr int power = P0 collect_unit_power<Tag, Units...> 。
using remainder = collect_unit_remainder_t<Tag, Units...> 。
};
template < class Tag, class Unit0, class. .. 單位>。
struct collect_unit<Tag, Unit0, Units...> {
static constexpr int power = collect_unit_power<Tag, Units...> 。
using remainder = decltype(std::tuple_cat(
std::declval<std::tuple<Unit0>>()。
std::declval<collect_unit_remainder_t<Tag, Units...>>()))。)
};
// 特質。結合任何具有相同Tag的單位。
template <class Tuple>
struct group_units。
template <class Tuple>
using group_units_t = typename group_units<Tuple> ::type。
template<>
struct group_units<std::tuple<> > {
using type = std::tuple<>。
};
template <class。單位>。
struct group_units<std::tuple<Units...> > {
private:
using Tag0 = first_tag_t<Units...> 。
using collect_t = collect_unit<Tag0, Units...> 。
public:
using type = decltype(std::tuple_cat(
std::declval<std::conditional_t<
collect_t::power != 0,
std::tuple<UnitPower<Tag0, collect_t::power>> 。
std::tuple<>>>()。
std::declval<group_units_t<typename collect_t:: remainder>()))。)
};
template <typename T, class ... 單位>。
class Scalar。
// 特質。兩個Scalars是否具有相同的基礎型別和相同的單位。
//以任何順序?。
template <class S1, class S2>
struct Scalars_compatible : public std::false_type{};
template <class S1, class S2>
constexpr bool Scalars_compatible_v = Scalars_compatible<S1, S2> ::value。
template <typename T1, class. Units1, typename T2, class...。Units2>。
struct Scalars_compatible<Scalar<T1, Units1...>, Scalar<T2, Units2...> >
: public std::bool_constant<is_tuple_permutation_v<
std::tuple<Units1...>, std::tuple<Units2...>>>
{};
template <typename T, class Tuple>
struct tuple_to_Scalar;
template <typename T, class Tuple>
using tuple_to_Scalar_t = typename tuple_to_Scalar<T, Tuple> ::type;
template <typename T, class. 單位>。
struct tuple_to_Scalar<T, std::tuple<Units...> > {
using type = Scalar<T, Units...> 。
};
template <class S1, class S2>
struct Scalar_product。
template <class S1, class S2>
using Scalar_product_t = typename Scalar_product<S1, S2> ::type;
template <typename T1, class. Units1, typename T2, class...。Units2>。
struct Scalar_product<Scalar<T1, Units1...>, Scalar<T2, Units2...> > {
using type = tuple_to_Scalar_t<
std::common_type_t<T1, T2> 。
group_units_t<std::tuple<Units1..., Units2...>> 。
};
template <class Unit>
struct invert_unit。
template <class Unit>
using invert_unit_t = typename invert_unit< Unit>:type。
template <class Tag, int P>
struct invert_unit<UnitPower<Tag, P> > {
using type = UnitPower<Tag, -P> 。
};
template <class S1, class S2>
struct Scalar_quotient。
template <class S1, class S2>
using Scalar_quotient_t = typename Scalar_quotient<S1, S2> ::type;
template <typename T1, class. Units1, typename T2, class...。Units2>。
struct Scalar_quotient<Scalar<T1, Units1...> , Scalar<T2, Units2...> > {
using type = tuple_to_Scalar_t<
std::common_type_t<T1, T2> 。
group_units_t<std::tuple<Units1..., invert_unit_t<Units2> ...>>。
};
using Distance_t = Scalar<double, UnitPower<M_, 1> > 。
using Time_t = Scalar<double, UnitPower<S_, 1> >。
使用Speed_t = Scalar_quotient_t<Distance_t, Time_t>。
using Acceleration_t = Scalar_quotient_t<Speed_t, Time_t>;
using Mass_t = Scalar<double, UnitPower<KG_, 1> > 。
using Energy_t = Scalar_product_t<Mass_t, Acceleration_t> 。
static_assert(Scalars_compatible_v<Energy_t, Scalar<double, UnitPower< KG_, 1>, UnitPower<M_, 1>, UnitPower<S_, -2> >)。
static_assert(Scalars_compatible_v<Scalar_quotient_t<Speed_t, Acceleration_t>, Time_t>) 。
注意你可能想限制你的operator , operator==, 等等需要Scalars_compatible_v。
