С++ 11 пользовательских литералов для единиц физических свойств

Я пытаюсь научиться использовать пользовательские литералы С++ 11 для единиц физических свойств. Вопрос в том, как мне избежать смешения этих единиц. Так что (8.0_kg + 8.0_km) --> дает ошибку. есть идеи, ребята? Я новичок в С++, будьте добры.

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


}

person WOT    schedule 06.03.2017    source источник
comment
Я бы сделал это, сделав их типами (struct/class), а не просто long double.   -  person NathanOliver    schedule 06.03.2017
comment
Вы можете посмотреть strong typedef для своей массы/длины.   -  person Jarod42    schedule 06.03.2017


Ответы (2)


Вам нужно определить свои собственные типы, так как вы не можете ограничить то, что представляет примитив.

Вы можете использовать "шаблон с тегами"1, чтобы избежать повторения операторов и т.п. и обеспечить безопасность типов.
Его можно расширить, чтобы компилятор проверял, например, 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 называет фантомные типы.

person molbdnilo    schedule 06.03.2017

Создайте классы, представляющие числовые значения различных единиц измерения. Так это делалось задолго до C++ 11.

Однако пользовательские литералы могут сделать инстанцирование более читабельным, потому что они помогают сохранить обычный порядок чисел и единиц :)

См. 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
person yeoman    schedule 06.03.2017