簡體   English   中英

用戶定義的類型 - 單位、轉換

[英]User defined types - units, conversions

我嘗試制作一些用戶定義的類型來表達單位,以便我可以強類型函數參數。 例如,長度為毫米,速度為每秒毫米,加速度為每秒毫米,等等。

到目前為止,我已經這樣做了:

template<typename T, typename mksUnit>
struct Value
{
    // data member
    T val;

    // constructor
    constexpr explicit Value(T d) : val(d) {}

    // operator overloads
    Value & operator +=(const Value &rhs) { val += rhs.val; return *this; }
    // other math and compare
    // operators, etc.
}

template<int meters, int kilo, int seconds>
struct mksUnit
{
    enum { m = meters, k = kilo, s = seconds };
};

有了這個,我可以做這樣的事情:

using meters = Value<double, mksUnit<1, 0, 0>>;
using mm = Value<double, mksUnit<-3, 0, 0>>;
constexpr mm operator""_mm(long double v) { return mm(static_cast<double>(v)); }
using mmpersec = Value<double, mksUnit<-3, 0, 1>>;
constexpr mmpersec operator""_mms(long double v) { return mmpersec(static_cast<double>(v)); }
using mmpersec2 = Value<double, mksUnit<-3, 0, 2>>;
constexpr mmpersec2 operator""_mms2(long double v) { return mmpersec2(static_cast<double>(v)); }

創建我可以使用的單位,例如:

mm dist = 5.5_mm;
mm dist1 = dist + 10_mm;
mmpersec velocity = mmpersec(50.0);
mmpersec2 accel = 100.0_mms2;

void set_accel(mmpersec2 accel) { _accel = accel; }

等等。

我需要在某些類型之間進行轉換,我正在尋找一種很好的方法來做到這一點。 我唯一的想法是從類繼承並將類型重載添加到派生類。

struct millimeters: public mm
{
    operator(meters) { return mm.val / 1000; }
}

或類似的東西。

我想做這樣的事情:

meters len = meters(5.0);
len += millimeters(25);

例如,這應該將 len 設置為 1.025。

我的問題是在如上所示派生的不同用戶定義類型之間添加轉換的最佳方法是什么。

我認為你從錯誤的方向解決你的問題。 您不想轉換任意單位,而是要轉換數量內的單位。

所以我會這樣開始:

struct Quantity {
    double value;
};

// Base Quantites
class Length : public Quantity {};
class Duration : public Quantity {};

// Base units
Length Meter() {
    Length l;
    l.value = 1;
    return l;
}

Length Millimeter() {
    Length l;
    l.value = 0.001;
    return l;
}

Duration Seconds() {
    Duration t;
    t.value = 1;
    return t;
}

現在我們整理了數量,我們可以開始轉換:

// It is a good Idea to use SFINAE here to enable this function
// only for derived classes of Quantity
template <class Quantity>
double transform(Quantity&& value, Quantity&& ratio) {
    return value.value / ratio.value;
}

派生單位的部分是棘手的:

template <class Q1, class Q2>
struct MultipliedQuantiy : public Quantity {};

// I would use SFINAE here too because it is a bad idea to 
// define a multiplication for all possible types.
template <class Q1, class Q2>
auto operator*(Q1 q1, Q2 q2) {
    MultipliedQuantiy<Q1, Q2> q;
    q.value = q1.value * q2.value;
    return  q;
}

作為一個例子,我們可以使用這個:

auto area = 1000.0*Millimeter()*(1000.0*Millimeter());
auto squareMeter = 1.0*Meter()*Meter();
double area_in_m2 = transform(area, squareMeter);

所以這是關於如何完成的基本想法。 實現其余的操作取決於您。 您還可以在很多地方使用 constexpr 來強制編譯時評估。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM