2008-11-16 3 views
5

У меня есть векторный класс, который содержит массив объектов типа "T", и я хочу реализовать 4 арифметических оператора, которые будут применять операцию для каждого элемента:C++: использование оператора двух внутренних типов как объекта функции

// Constructors and other functions are omitted for brevity. 
template<class T, unsigned int D> 
class Vector { 

public: 
    // Add a value to each item: naive implementation. 
    void operator += (const T&) { 
     for (int i = 0; i < D; ++i) { 
      data[i] += value; 
     } 
    } 
    void operator -= (const T&) { ... } 
    void operator *= (const T&) { ... } 
    void operator /= (const T&) { ... } 

private: 
    T items[D]; 
}; 

Поскольку операторы будут содержать один и тот же шаблонный код (цикл по каждому элементу и применяя соответствующую операцию), я думал, что я мог бы обобщать:

template<class T, unsigned int D> 
class Vector { 

public: 
    void operator += (const T& value) { do_for_each(???, value); } 
    void operator -= (const T& value) { do_for_each(???, value); } 
    void operator *= (const T& value) { do_for_each(???, value); } 
    void operator /= (const T& value) { do_for_each(???, value); } 

private: 
    void 
    do_for_each(std::binary_function<void, T, T>& op, T value) { 
     std::for_each(data, data + D, std::bind2nd(op, value)); 
    } 

    T data[D]; 
}; 

Теперь проблема в том, как я прохожу оператор, который принимает два внутренних ic типы и возвращает void до do_for_each, как показано в примере выше? C++ не позволяет мне делать этот трюк для встроенных типов ("T::operator+=" не будет работать, если "T" - "int").

+0

Вы можете исправить `data` против` `деталей ... – Alastair 2008-11-16 03:44:23

+0

спасибо, фиксированная он тоже ниже – 2008-11-16 03:48:34

ответ

8

Во-первых, вы должны действительно вернуть ссылку от вашего оператора + =, так как вы можете использовать их для реализации оператора +, оператора и т. Д. Я изменю это соответственно.

Кроме того, ваш do_for_each должен быть шаблоном, поскольку он должен знать точный тип объекта функции, поскольку объекты двоичной функции не являются классами полиморфов. Для реальной работы, вы хотите использовать std::transform:

template<class T, unsigned int D> 
class Vector { 

public: 
    Vector& operator += (const T& value) { 
     do_for_each(std::plus<T>(), value); 
     return *this; 
    } 

    Vector& operator -= (const T& value) { 
     do_for_each(std::minus<T>(), value); 
     return *this; 
    } 

    Vector& operator *= (const T& value) { 
     do_for_each(std::multiplies<T>(), value); 
     return *this; 
    } 

    Vector& operator /= (const T& value) { 
     do_for_each(std::divides<T>(), value); 
     return *this; 
    } 

private: 
    template<typename BinFun> 
    void do_for_each(BinFun op, const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(op, value)); 
    } 

    T data[D]; 
}; 

std::transform просто пройти каждый элемент функционального объекта, и присваивает результат обратно итератор данного в качестве третьего аргумента.

2

Вы действительно должны взглянуть на Boost Operators, библиотеку только для заголовка, которая действительно упрощает создание ортогональных и последовательных арифметических перегрузок операторов.

В частности: вы можете обнаружить, что получение boost::operators::integer_arithmatic<T> сэкономит вам много повторений этого класса.

1

Я думаю, что лампочка находится на правильном пути и отвечает на точный вопрос.
Но я думаю, что это неправильное решение.

Я предпочел бы не использовать do_for_each(), но лучше использовать зЬй :: преобразование() непосредственно:

template<class T, unsigned int D> 
class Vector 
{ 

    public: 
    Vector& operator += (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::plus<T>(),value)); 
     return *this; 
    } 

    Vector& operator -= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::minus<T>(),value)); 
     return *this; 
    } 

    Vector& operator *= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::multiplies<T>(),value)); 
     return *this; 
    } 

    Vector& operator /= (const T& value) { 
     std::transform(data, data + D, data, std::bind2nd(std::divides<T>(),value)); 
     return *this; 
    } 

    private: 
    T data[D]; 
};