2008-11-16 4 views
5

저는 "T" 유형의 객체 배열을 포함하는 벡터와 같은 클래스를 가지고 있으며 각 항목에 연산을 적용 할 4 개의 산술 연산자를 구현하려고합니다. C++ : 함수 객체로 두 가지 내장 유형의 연산자 사용

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

지금, 문제는, 내가 어떻게

을 통과 할 : 연산자가 동일한 상용구 코드를 포함하기 때문에 (모든 요소를 ​​통해 반복하고 적절한 동작을 적용)

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

, 나는 그것을 일반화 수 있다고 생각 2 개의 intrins를 취하는 연산자 ic 형식을 사용하고 위의 예에서 설명한대로 void ~ do_for_each을 반환합니까? C++은 내재적 인 타입에 대해이 트릭을 할 수 없습니다. "T""int"이면 "T::operator+="이 작동하지 않습니다.

+0

당신은''items' ... – Alastair

+0

덕분에, 대 data' 고정을 고정 할 수 있습니다 그것도 아래에 –

+0

이런 질문은 친구가 친구 오버로드 운영자를 허용하지 않는 이유는 무엇입니까 – Jonathan

답변

8

먼저 operator + =에서 참조를 반환해야합니다. 나중에 연산자 +, 연산자 등을 구현할 수 있으므로 참조를 반환해야합니다. 나는 그것을 적절하게 바꿀 것이다.

또한 이진 함수 객체가 polymorph 클래스가 아니기 때문에 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

은 함수 객체에 각 요소를 전달하고 세 번째 인수로 주어진 반복자에 결과를 다시 할당합니다.

+0

나는 정확히 똑같은 것을 쓰는 과정에있었습니다! :) 건배, +1! –

+0

당신은 연산자에서 const 참조를 반환해야합니다. 이렇게하면 읽기/쓰기가 어렵습니다. (v + = v2) - = v3 – SoapBox

+0

SoapBox : 특별한 이유가 없습니다. 그것을 금한다. 또한 const가 아닌 것을 반환하면 가장하지 않는 것을 수행합니다. 이것은 최소한의 놀라움의 원칙에 반하여 노력합니다. f (a + = b)를하는 것은 매우 합리적입니다. 예를 들면. –

2

실제로 직각 및 일관된 산술 연산자 오버로드를 간단하게 만드는 헤더 전용 라이브러리 Boost Operators을 살펴보아야합니다.

구체적으로 : boost::operators::integer_arithmatic<T>에서 파생 된 것이이 클래스를 반복적으로 저장한다는 것을 알 수 있습니다.

1

litb가 올바른 트랙에 있고 정확한 질문에 대답했다고 생각합니다.
하지만 이것이 잘못된 해결책이라고 생각합니다.

차라리 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]; 
};