2014-01-30 4 views
3

약간 비대칭 적으로 추가 된 클래스를 만들고 있습니다. 불만이 오기 전에 반드시 비대칭입니다. 두 개체가 함께 추가 될 때 발생하는 변환 (시간이 조금 걸리는 작업)이 있으며 변환은 가장 자연스럽게 오른쪽 summand와 관련하여 발생합니다. C++에서 연산자 결합 성을 오버로드 할 수 있습니까?

추가 할 두 Foo의 위해서는 ... 여기에 무슨 일이 일어나고 있는지의 일반적인 예입니다,

class Foo { 
    char _fav; 
    int _prop; 

public: 
    const char fav() const {return _fav;} 
    const int prop() const (return _prop;} 
    void changeFav(char); // complicated method that also changes _prop 
    void changeProp(int); // straightforward method 
} 

Foo 
operator + (Foo A, Foo B) { 
    Foo sum; 
    if (A.fav() != B.fav()) A.changeFav(B.fav); 
    sum.changeProp(A.prop() + B.prop()); 
    return sum; 
} 

을이 콘크리트를 만들기 위해, 그들은 그렇게 선택의 여지가 있어야합니다, 같은 _fav이 필요합니다 어느 것으로 변환 할 것인가. Foo의 세부 정보를 기반으로 왼쪽 summand를 오른쪽 summand와 일치하도록 변경하는 것이 가장 자연스러운 것입니다.

그러나

, 일 : 이미 C 같은 _fav은 다음 changeFavD 두 번 호출이

Foo A,B,C; 
Foo D = A + B + C; // D = (A + B) + C 
Foo E = A + (B + C); 

A 경우 (한 번 B._favA._fav 변경 한 후 다시 C._fav(A+B)._fav을 변경) 및 E (B._fav에서 C._fav으로 변경)에 한 번 후자를 선호하지만 사용자가 여러 추가를 위해 괄호를 사용하지 않도록하고 싶습니다.

이런 일이 발생하도록 operator +의 결합성에 과부하가 걸릴 수 있습니까?

+0

'연산자 +'는 아무 것도 반환하지 않으며 두 개의 멤버 함수에 반환 유형이 없습니다. –

+1

완전한 대답을 제공 할 수는 없지만 간단히 말해서 foo를 반환하지 말고 오른쪽 피연산자를 foo가 아닌 다른 것으로 만드십시오. 이것은 내 혼에서 입력 한 의식의 흐름입니다. –

+0

@LightnessRacesinOrbit 네, 이것은 단지 잘못된 예일 뿐이므로 어떤 일이 벌어지고 있는지 볼 수 있습니다. 실제 코드가 아닙니다. – PengOne

답변

2

오버로드 운영자는 5 절은 연산자 우선 순위와 연산을 지정하는 제 5

에 지정된 구문 규칙을 준수하십시오.

+0

감사합니다. 좋은 해킹을하지 않으면, 나는 이것을 받아 들일 것이다. – PengOne

2

아니요. 그렇다면 왜 오른쪽 피연산자의 선호도를 변경하지 않으시겠습니까?

+0

그것은 복잡하고 (진짜)'Foo'의 기술 세부 사항과'+'가'Foo'를 의미하는 것에 들어갑니다. "아니오"에 대해 자세히 설명해 주시겠습니까? 이것은 돌로 쓰여졌 을까요 아니면 지금까지 한 번도 본 적이 없습니까? – PengOne

+2

@ PengOne : 만약 당신의 질문이 "내가'+'의 연관성을 바꿀 수 있다면 대답은"할 수 없다 "입니다. 내가 "한 번도 본 적이 없다"는 것만은 아닙니다. 언어 문법의 사실입니다. –

+2

@LightnessRacesinOrbit : 그러나 'A + B'가 반대의 결합 성을 갖는 것처럼 행동하는 것이 가능합니다. 이는 훨씬 더 많은 코드라면 거의 동일한 결과입니다. –

3

해킹을 할 수 있습니다. 다른 유형을 사용하여 조작의 중간 결과를 보유해야하며 암시 적 형변환을 사용하여 결과를 평가할 수 있습니다.

#include <vector> 
#include <cstdio> 

struct S { 
    S(int x) : val(x) { } 
    int val; 
}; 

struct Comparison { 
    std::vector<S> operands; 
    explicit Comparison(S x) 
    { 
     operands.push_back(x); 
    } 
    operator S() 
    { 
     auto i = operands.begin(), e = operands.end(); 
     S prev = *i; 
     for (i++; i != e; i++) { 
      S cur = *i; 
      if (prev.val >= cur.val) 
       return S(0); 
      prev = cur; 
     } 
     return S(1); 
    } 
    void append(const Comparison &a) 
    { 
     operands.insert(
      operands.end(), 
      a.operands.begin(), 
      a.operands.end()); 
    } 
    void append(const S &a) 
    { 
     operands.push_back(a); 
    } 
}; 

Comparison operator<(const Comparison &left, const Comparison &right) 
{ Comparison result(left); result.append(right); return result; } 
Comparison operator<(const Comparison &left, const S &right) 
{ Comparison result(left); result.append(right); return result; } 
Comparison operator<(const S &left, const Comparison &right) 
{ Comparison result(left); result.append(right); return result; } 
Comparison operator<(const S &left, const S &right) 
{ Comparison result(left); result.append(right); return result; } 

int main() 
{ 
    S x(0); 
    x = S(0) < S(1) < S(2) < S(3); 
    std::printf("0 < 1 < 2 < 3 = %d\n", x.val); 
    x = S(0) < S(1) < S(3) < S(2); 
    std::printf("0 < 1 < 3 < 2 = %d\n", x.val); 
    return 0; 
} 

이러한 상황에서, 그러나, 나는 + 연산자를 도랑 빠르게 될 것이다 : 여기에 C++에서 파이썬 스타일 비교 연산자를 구현하는 방법의 예입니다. 수학에서 +에 대한 규칙이므로 연관 및 교환 가능하지 않은 연산에 대해서는 +을 사용하지 않는 것이 좋습니다. 대신 템플릿을 사용하는 가변 함수를 사용하여 원하는 계산을 수행 할 수 있습니다.

C++ 표준 5 절에서
+0

나는이 정신을 좋아한다. '+'에 관해, 수학에서 2 개의 선형 변환을 추가 할 때, 먼저 같은 기초로 표현되어야합니다. 이것은 제 예제와 매우 비슷합니다. – PengOne

+0

@PengOne : 추가 할 기준을 사용하여 선형 변환을 표현할 필요는 없습니다. 모든 선형 변환을 기초를 사용하여 표현할 수있는 것은 아닙니다. "(f + g) (x) = f (x) + g (x)"를 정의 할 수 있습니다. –

+0

사실,하지만 저는'_fav'가 선택된 기초이고'_prop'가 그 기초가되는 매트릭스 표현이면 내 예제가 자연 스럽다는 것을 설명하고 있습니다. – PengOne

3

킨다,하지만 당신은 그 "방법"을 좋아하지 않을 것입니다.

먼저, Boost.Proto 설명서를 읽고 이해해야합니다. 그런 다음, 모든 표현식 트리를 변환하여 조작 순서를 반대로 변환하는 방법을 알아야합니다. 그런 다음 표현식 트리를 최종 사용자에게 투명하게 평가해야합니다. 가능할 수 있니? 나는 Proto를 많이 사용하지는 않았지만, this article on Proto-based optimizations과 비슷한 것이 시작하는 데 도움이 될 수 있습니다.