2008-11-16 23 views
5

Mam klasę podobną do wektora, która zawiera tablicę obiektów typu "T" i chcę zaimplementować 4 operatory arytmetyczne, które zastosują operację na każdym elemencie:C++: Używanie operatora dwóch typów wewnętrznych jako obiektu funkcji

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

Ponieważ operatorzy będą zawierać ten sam kod szablonowe (zapętlenie nad każdym elementem i stosując odpowiednią operację), myślałem, że mógłbym go uogólniać:

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

teraz problemem jest to, w jaki sposób przekazać operator, który przyjmuje dwie wartości wewnętrzne ic typy i zwraca void do do_for_each, jak pokazano w powyższym przykładzie? C++ nie pozwala mi zrobić tej sztuczki dla typów wewnętrznych ("T::operator+=" nie zadziała, jeśli "T" jest "int").

+0

Może chcesz naprawić '' items' data' vs ... – Alastair

+0

Dzięki, stałe też poniżej –

+0

Pytania takie jak to, dlaczego przyjaciele nie pozwalają przeciążać operatorów – Jonathan

Odpowiedz

8

Najpierw powinieneś zwrócić referencję od operatora + =, ponieważ możesz później użyć ich do wdrożenia operatora +, operatora itd. Zmienię to odpowiednio.

Również twój do_for_each musi być szablonem, ponieważ musi znać dokładny typ obiektu funkcji, ponieważ obiekty funkcji binarnych nie są klasami polimorficznymi. Dla rzeczywistego działania, którego chcesz użyć 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 będzie po prostu przejść każdy element do obiektu funkcyjnego i przypisuje wynik z powrotem do danego iteracyjnej jako trzeci argument.

+0

Byłem właśnie w trakcie pisania dokładnie to samo! :) Pozdrawiam, +1! –

+0

Powinieneś zwrócić referencję do stałej z operatorów, więc wykonanie tej czynności (która jest naprawdę trudna do odczytania/wymyślenia) nie jest możliwe: (v + = v2) - = v3 – SoapBox

+0

SoapBox: nie widzę szczególnych powodów, aby zabrońcie tego. Ponadto, gdy zwrócisz wartość stałą, robisz to, czego większość nie robi. Jest to sprzeczne z zasadą najmniejszego zaskoczenia. To całkiem rozsądne, aby zrobić f (a + = b); na przykład. –

2

Naprawdę powinieneś rzucić okiem na Boost Operators, bibliotekę tylko nagłówkową, która naprawdę upraszcza tworzenie ortogonalnych i spójnych przeciążeń operatorów arytmetycznych.

W szczególności: może się okazać, że wynikająca z boost::operators::integer_arithmatic<T> oszczędza dużo powtórzeń tej klasy.

1

Myślę, że litb jest na właściwej ścieżce i odpowiedział na dokładne pytanie.
Ale myślę, że to niewłaściwe rozwiązanie.

wolałbym nie używać do_for_each(), ale raczej użyć std :: transformacji() bezpośrednio:

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]; 
}; 
Powiązane problemy