C ++: Есть ли менее подробный способ представления пользовательских числовых типов? - PullRequest
3 голосов
/ 06 октября 2011

Мне нужно изобразить Вольт, Ампер и Ватт и их отношения (например, W = V * I) ..

Это то, с чем я пришел, но это кажется действительно многословнымЛюбая идея о том, как сделать это более кратким?

#include <stdio.h>
#include <iostream>


template<class T>    
class double_val {   
public:
    explicit double_val(double val):_val(val) { };
    double_val(const T& other) {
        _val = other._val;
    }
    T& operator=(const T &other) {
        _val = other._val;
        return *this;
    }
    T operator+ (const T& other) const {
        return T(this->_val + other._val);
    }
    T operator+ (double val) const {
        return T(this->_val + val);
    }
    T operator- (const T& other) const {
        return T(this->_val - other._val);
    }
    T operator- (double val) const {
        return T(this->_val - val);
    }
    T operator* (const T& other) const {
        return T(this->_val * other._val);
    }
    T operator* (double val) const {
        return T(this->_val * val);
    }
    T operator/ (const T& other) const {
        return T(this->_val / other._val);
    }
    T operator/ (double val) const {
        return T(this->_val / val);
    }
    bool operator== (const T& other) const{
        return this->_val == other._val;
    }
    bool operator!= (const T& other) const{
        return this->_val != other._val;
    }
    bool operator > (const T& other) const{
        return this->_val > other._val;
    }
    bool operator >= (const T& other) const{
        return this->_val >= other._val;
    }
    bool operator < (const T& other) const{
        return this->_val < other._val;
    }
    bool operator <= (const T& other) const{
        return this->_val <= other._val;
    }
    void val(double val){
        _val = val;
    }
    double val() const {
        return _val ;
    }
    virtual const char* name() const = 0;

private:
    double _val;
};
template<class T>
std::ostream& operator<<(std::ostream &os, const double_val<T> &t) {
    return os << t.val() <<  " " << t.name();
}


class Amper:public double_val<Amper> {
public:
    Amper(double val):double_val<Amper>(val) {}
    const char* name() const {
        return "Amper";
    }
};

class Volt:public double_val<Volt> {
public:
    Volt(double val):double_val<Volt>(val) {}
    const char* name() const {
        return "Volt";
    }
};

class Watt:public double_val<Watt> {
public:
    Watt(double val):double_val<Watt>(val) {}
    const char* name() const {
        return "Watt";
    }
};

// Watt = I * V
Watt operator* (const Volt &v, const Amper& a) {
    return Watt(a.val() * v.val());
}
Watt operator* (const Amper &a, const Volt& v) {
    return Watt(a.val() * v.val());
}

// Volts = Watts/Ampers
Volt operator / (const Watt &w, const Amper& a) {
    return Volt(w.val() / a.val());
}

// Ampers = Watts/Volts
Amper operator / (const Watt &w, const Volt& v) {
    return Amper(w.val() / v.val());
}



int main(int argc, char **argv) {
    using namespace std;
    Watt w = Volt(66) * Amper(7);
    Amper a = w / (Volt(646) * Volt(444));

    cout << a << endl;

    return 0;
}

(примечание: я намеренно опустил оператор double (), так как хотел избежать запрещенных операций, таких как Volt (4) + Watt (6))

Ответы [ 4 ]

10 голосов
/ 06 октября 2011

Существует действительно менее многословный способ в библиотечной форме, Boost.Units , который определяет единицы SI как экземпляры шаблонов классов безопасного типа.

В частности,он определяет единицы volt(s), ampere(s) и watt(s).

3 голосов
/ 06 октября 2011

Boost.Units - это хорошее решение для ваших нужд, так как оно обеспечивает представление напряжения, ампер, ватт и соответствующих операторов из коробки.

Boost.Operators решает эту проблему для общего случая пользовательских числовых типов, которые не являются единицами СИ.

2 голосов
/ 06 октября 2011

Кроме того, Boost Utility содержит средства, которые значительно упрощают написание всех операций оператора в таких случаях.


Я недавно сделал пример здесь: Можете ли вы установить максимальный предел для целого числа (C ++)?

2 голосов
/ 06 октября 2011

Если клиентский код взаимодействует, вы можете удалить логические операции, используя std :: rel_ops . rel_ops определяет группу логических операторов в терминах ваших == и <операторов. </p>

Однако это проблематично - это заставляет клиента использовать rel_ops, а rel_ops неожиданно позволяет любому классу с оператором == и <сравниваться со всеми другими операторами. Это, вероятно, не то, что вы хотите. </p>

IMO, лучший вариант - использовать библиотеку boost операторов , которая кажется идеальной для числовых типов, поскольку она предоставляет все различные операторы, которые вы могли бы хотеть для числового типа. Вы просто определяете несколько базовых операторов, а остальные заполняют в зависимости от вашей спецификации. Чтобы украсть из примера документации буста:

template <class T>
class point    // note: private inheritance is OK here!
    : boost::addable< point<T>          // point + point
    , boost::subtractable< point<T>     // point - point
    , boost::dividable2< point<T>, T    // point / T
    , boost::multipliable2< point<T>, T // point * T, T * point
      > > > >
{
public:
    point(T, T);
    T x() const;
    T y() const;

    point operator+=(const point&);
    // point operator+(point, const point&) automatically
    // generated by addable.

    point operator-=(const point&);
    // point operator-(point, const point&) automatically
    // generated by subtractable.

    point operator*=(T);
    // point operator*(point, const T&) and
    // point operator*(const T&, point) auto-generated
    // by multipliable.

    point operator/=(T);
    // point operator/(point, const T&) auto-generated
    // by dividable.
private:
    T x_;
    T y_;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...