2017-03-06 15 views
2

物理的な単位の単位に対して11のユーザー定義のリテラルを使用する方法を学習しようとしています。問題は、これらのユニットの混在を避けるにはどうしたらいいですか?だから(8.0_kg + 8.0_km) - >はエラーです。どんなアイディアですか?私はC + +に新しいです、親切です。C++物理的な単位の単位のユーザー定義のリテラル

class Mass{ 
    public:   
     //Mass(){ 
     // cout << "only Mass units allowed in here" << endl; 
     //} 
     //~Mass(); 
     long double getWeight(long double a);   
     double car, house, cat; 

    private: 
     long double a; 


    }; 


long double Mass::getWeight(long double w) { 

    cout << "returning argument: " << w << '\n'<< endl; 
    return 0; 
} 


long double operator"" _km(long double d) { return d * 1000.0; } 
long double operator"" _m (long double d) {return d;} 
long double operator"" _cm(long double d) { return d/100.0; } 

long double operator"" _tonne(long double m) { return m * 1000.0 ; } 
long double operator"" _kg(long double m) { return m ; } 
long double operator"" _lb(long double m) { return m * 0.453592; } 

long double getDistance(long double d){ 
    long double starting_d = 61.0_kg; 
    long double total_d = d + starting_d; 
    cout << "the distance I have run is: " << total_d << endl; 
    return 0; 
} 

int main() { 


    cout << 6.0_km << endl; 
    cout << 6.0_km + 3.0_m << endl; 
    cout << 6.0_km + 3.0_m + 15.0_cm << '\n' << endl; 

    cout << 8.0_tonne << endl; 
    cout << 8.0_km + 4.0_kg << endl; 
    cout << 8.0_km + 4.0_kg + 21.0_lb << '\n' << endl; 


    long double distance = 5.45_km; 
    getDistance(distance); 

    Mass obj1; 
    obj1.getWeight(13.96_lb); 

    cout << "This is clearly wrong: "<< 8.0_km + 4.0_kg << endl; 

    obj1.getWeight(10.96_km); // so is this 


} 
+6

'long double'の代わりに' struct'/'class'をタイプすることでやります。 – NathanOliver

+0

[strong typedef](http://stackoverflow.com/questions/28916627/strong) -typedefs)を使用します。 – Jarod42

答えて

2

異なる単位の数値を表すクラスを作成します。つまり、http://en.cppreference.com/w/cpp/language/user_literal

class MassKg 
{ 
    double value; 

    // public c'tor, numeric operators, &c. 
}; 

// ... 

MassKg mass(5.0); 
DistanceM distance(3.0); 
auto c = mass * distance; // may yield an instance of TorqueKgM, or MomentumKgM, therefore 
// explicit functions/methods are preferrable for mixed 
// multiplication or division 
auto mass2 = mass + MassKg(2.0); // yiels an instance of MassKg 
auto invalid = mass + distance; // compile time error 
+0

あなたの例では、私はちょうどこれを残すhttp://en.cppreference.com/w/cpp/language/user_literal – jamek

+0

@ Jarod42はよかった変数の命名、ありがとう^^ – yeoman

+0

良い、私は意味--.-愚かなオートコレクト。 – yeoman

6
を参照番号とユニットの通常の順序:)

を維持するのに役立ちますので、C++ 11

カスタムリテラルは、しかし、インスタンス化をより読みやすくすることができます前に、それは長い間以来行われています方法です

プリミティブが表すものを制限することはできないので、独自の型を定義する必要があります。

"タグ付きテンプレート" を使用すると、オペレータなどの繰り返しを避け、型を安全に保つことができます。
これを拡張すると、たとえばdistance * distance = areaまたはspeed * time = distanceがコンパイラによってチェックされます。ここで

が短い例です:

template<typename Kind> 
struct Value 
{ 
    long double value; 
    Value& operator+= (Value v) { value += v.value; return *this; } 
}; 

template <typename Kind> 
Value<Kind> operator+ (Value<Kind> lhs, Value<Kind> rhs) { return lhs += rhs; } 

// These types don't need definitions; we only need some unique type names. 
struct M; 
struct D; 

using Mass = Value<M>; 
using Distance = Value<D>; 

Mass operator"" _kg(long double d) { return { d };} 
Mass operator"" _lb(long double d) { return { d * 0.453592 };} 

Distance operator"" _km(long double d) { return { d * 1000 };} 
Distance operator"" _mile(long double d) { return { d * 1609 };} 

int main() 
{ 
    // OK 
    Distance d = 1.2_km + 0.2_mile; 
    // OK 
    Mass m = 2.3_kg + 1.4_lb;  
    // invalid operands to binary expression ('Distance' (aka 'Value<D>') 
    // and 'Mass' (aka 'Value<M>')) 
    Distance d2 = 2.4_km + 1.2_kg; // Nope 
} 

1)私はC++で確立用語はないと思うが、それはHaskellはphantom typesといいものに非常に似ています。

関連する問題