2008-11-16 13 views
5

Tengo una clase similar a un vector que contiene una matriz de objetos de tipo "T", y quiero implementar 4 operadores aritméticos, que aplicarán la operación en cada elemento:C++: Usando operador de dos tipos intrínsecos como objeto de función

// 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]; 
}; 

Debido a que los operadores contendrán el mismo código repetitivo (bucle sobre cada elemento y la aplicación de la operación apropiada), pensé que podía generalizar:

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]; 
}; 

Ahora, el problema es, ¿cómo puedo pasar un operador que toma dos intrincaciones ic tipos y devuelve void a do_for_each, como se muestra en el ejemplo anterior? C++ no me deja hacer este truco para tipos intrínsecos ("T::operator+=" no funcionará si "T" es "int").

+0

Es posible que desee fijar '' 'de los artículos data' vs ... – Alastair

+0

gracias, fijo a continuación también –

+0

Preguntas como esta son las razones por las que los amigos no dejan que los amigos sobrecarguen a los operadores – Jonathan

Respuesta

8

Primero, realmente debe devolver una referencia de su operador + =, ya que luego puede usarlos para implementar operator +, operator-, etc. Voy a cambiar eso en consecuencia.

Además, tu do_for_each tiene que ser una plantilla, ya que debe conocer el tipo exacto del objeto de función, ya que los objetos de función binaria no son clases polimórficas. Para la operación real, que desea utilizar 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 se acaba de pasar cada elemento al objeto de función, y asigna el resultado de vuelta al iterador dado como el tercer argumento.

+0

¡Estaba escribiendo exactamente lo mismo! :) ¡Salud, +1! –

+0

Debería devolver una referencia constante de los operadores, por lo que no es posible hacer esto (que es realmente difícil de leer/deducir): (v + = v2) - = v3 – SoapBox

+0

SoapBox: no veo razones particulares para prohibir eso. Además, cuando regresas sin const, haces lo que la mayoría no hace. Esto lucha contra el principio de la menor sorpresa. Es perfectamente razonable hacer f (a + = b); por ejemplo. –

2

Debería echarle un vistazo a Boost Operators, una biblioteca de solo encabezado que realmente simplifica la creación de sobrecargas de operador aritmético ortogonal y consistente.

Específicamente: puede encontrar que derivar de boost::operators::integer_arithmatic<T> le ahorra mucha repetición de esta clase.

1

Creo que litb está en la pista correcta y respondió la pregunta exacta.
Pero creo que esta es la solución incorrecta.

yo preferiría no utilizar el do_for_each(), sino más bien utilizar el std :: transformo() directamente:

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]; 
}; 
Cuestiones relacionadas