4

私は、 GoingNative 2012 (23:00 から)で Stroustrup によって提示されたユーザー定義リテラルを使用して、ユニットの実装をいじってみました。コードは次のとおりです。

 #include <iostream>

 using std::cout;
 using std::endl;

 template<int M, int K, int S> 
 struct Unit { // a unit in the MKS system
   enum {m=M,kg=K,s=S}; 
 };

 template<typename Unit> // a magnitude with a unit
 struct Value {
   double val;
   constexpr Value(double d) : val(d) {}
 };

 using Meter = Unit<1,0,0>;
 using Second = Unit<0,0,1>;

 using Distance = Value< Meter >;
 using Time = Value< Second >;
 using Velocity = Value< Unit<1,0,-1> >;

 constexpr Value<Meter> operator "" _m(long double d)
 // a f-p literal with suffix 'm'
 {
   return Distance(d);
 }

 constexpr Value<Second> operator"" _s(long double d)
 // a f-p literal with suffix 's'
 {
   return Time(d);
 }

 constexpr Velocity operator/(Distance d, Time t)
 {
   return ( d.val / t.val );
 }

 int main(void)
 {
    Distance s = 100._m;
    Time t = 22._s;
    Velocity v = s/t;

    cout << "s " << s.val << "\nt " << t.val << endl;
    cout << "v " << v.val << endl;

   return 0;
 }

ご覧のとおり、自由に を定義しoperator/て速度を計算しました。出力は次のとおりです (gcc-4.7 が必要です)。

$ g++ -std=c++0x test_units_02.cc && ./a.out
s 100
t 22
v 4.54545

ここまでは順調ですね。ここで、単位表現を含む文字列を構造体 Unit (または Value?) に追加したいと考えています。どんな方法でも書けるようになりたい

cout << "v " << v.val << v.unit << endl;

そして、次のようなものを取得します

v 4.54545 m^1 s^-1

また

v 4.54545 m^1 kg^0 s^-1

確認用なので綺麗である必要はありません。そして、それを行う方法を学びます;)。

もちろん、洗練された解決策は、コンパイル時にすべてを評価することです。

私はそれにいくつかのショットを持っていましたが、結果のない試みであなたを退屈させたり混乱させたりすることはありません...

4

2 に答える 2

6

まず、unitメンバーを に追加しValueます。

 template<typename Unit> // a magnitude with a unit
 struct Value {
   double val;
   constexpr static Unit unit = {};
   constexpr Value(double d) : val(d) {}
 };

次に、ストリーム出力演算子を書きます。

 template<int M, int K, int S>
 std::ostream &operator<<(std::ostream &os, Unit<M, K, S>) {
   return os << "m^" << M << " kg^" << K << " s^" << S;
 }

コンパイル時に文字列を生成することは可能ですが、constexprコンパイル時の文字列クラス (例: boost::mpl::string) と 10 進数の書式設定が必要です。これらはすべて実行可能ですが、この場合は特に価値がありません。

于 2012-11-14T14:55:00.770 に答える
1

Unit必要な情報が既にあるので、 に関数を追加するValueか、 をオーバーロードしてこれを行うことができoperator<<ます。

template<typename U>
struct Value
{
    double val;
    constexpr Value(double d) : val(d) {}

    std::string Units() const
    {
        return "m^" + to_string(U::m) + 
               " kg^" + to_string(U::kg) +
               " s^" + to_string(U::s);
    }
};

template <typename U>
std::ostream& operator<<(std::ostream& out, Value<U> val)
{
    out << val.val
        << " m^" << U::m << " kg^" << U::kg << " s^" << U::s;
    return out;
}

ジェネリックを提供することもできますoperator/:

template <typename U1, typename U2>
Value<Unit<U1::m - U2::m, U1::kg - U2::kg, U1::s - U2::s>>
operator/(Value<U1> v1, Value<U2> v2)
{
    return (v1.val / v2.val);
}

これにより、柔軟性が向上します。

void demo()
{
    auto accel = Distance(100) / Time(22) / Time(1);
    cout << accel << endl; // Print with units.
    cout << accel.val << endl; // Print without units.
    cout << accel.Units() << endl; // Print only units.
}
于 2018-03-30T13:46:27.700 に答える