2010-05-30 3 views
15

p->m(*p).m에 대한 구문 설탕 일 뿐이라고 생각하지 않습니까? 다음과 같이 기본적으로 내가 쓴 모든 operator->이 구현 될 수 있었다 :왜 연산자 -> 수동으로 과부하 될 수 있습니까?

Foo::Foo* operator->() 
{ 
    return &**this; 
} 

내가 p->m(*p).m 것보다 다른 것을 의미 할 것입니다 어떤 경우가 있습니까? > ... 운용자를 오버로드 할 필요가 없습니다

+1

이 재귀가있는 클래스에 대해'x-> y'는'(x.operator ->()) -> y'로 해석된다는 것은 당연한 것처럼 보입니다. 어쩌면 그들은 재귀를 허용하기 위해 해를 끼치 지 않을 것이라고 생각했기 때문에 그것을 금지하지 않았을 까? 적어도 나는 ARM에서 그것에 대한 설명을 찾을 수 없었다. –

답변

18

operator->()는 반환 형식이 수 있지만 의 기괴한 구분이 암시 적으로 반복을 를 호출되고 있습니다. 이 동작은 스마트 포인터와 같은 맥락에서 다른 객체에 대한 프록시로서 행동하는 객체를 사용하는 데 필요한 때 내가 할 수 있지만

struct X { 
    int foo; 
}; 

struct Y { 
    X x; 
    X* operator->() { return &x; } 
}; 

struct Z { 
    Y y; 
    Y& operator->() { return y; } 
}; 

Z z; 
z->foo = 42;   // Works! Calls both! 

가 나는 계기를 기억 :이 보여주는 가장 분명한 방법은 코드입니다 세부 사항을 기억하지 못합니다. 내가 기억하는 것은이 이상한 특별한 경우를 사용하여 a->b 구문을 사용하여 의도 한대로 작동 할 수있는 동작을 얻을 수 있다는 것입니다. 비슷한 방법으로 (*a).b을 얻을 수있는 방법을 찾지 못했습니다.

이 질문에 대한 답변이 확실하지 않습니다. 정말로 나는 "좋은 질문이지만, 그것보다 더 이상합니다!"라고 말하고 있습니다.

+1

+1하지만 'operator->'가 언어에 포함되어 있어도이 이상한 규칙을 시행 할 수 있습니다. 맞습니까? 기술적으로는 신택스 설탕 - 신랄한 시럽 *보다 약간 더 많을 것입니다. – fredoverflow

+2

언어 스펙이 컴파일러에게'a-> b'를'(* a) .b'로 재 작성하도록 요청했다면 재귀 적으로'operator *()'를 호출하는 것이 합리적입니까? 아니요, 때로는 "끝까지"하기 전에 멈추어야합니다 (예 : 포인터/포인터와 유사한 객체를 반환합니다. 예를 들어, 마지막으로 지적 된 객체를 반환하는 대신 수정 가능). 실제로 "적절한"2-arg 연산자가 아니기 때문에'operator ->()'재귀 기묘함이 필요합니다 (필요합니까?) - 두 번째 "인수"는'struct' 필드 이름이어야합니다. C++ 유형 시스템에서 표현 될 수 있습니다. –

+3

추신 : 나는 그것을 통칭 당밀이라고 부른다 * - 크롤링에 대한 나의 이해를 늦춘다 ... : P –

0

당신은 다른 한편으로 등 변수 (액세스 계산) 또는 일부 안전 점검을 증가 같은 다른 작업을 수행 할 수 있습니다, 내가 가진

-1

나는 그것이 shared_ptr <> boost (예를 들어)에 사용 된 것 같아요. 그 (것)들은 특별한 포인터이지만 (참조 카운트 afaik) 일반 포인터와 같은 "모양"을 갖게합니다.

+7

그게 나에게 두려운 게 아무 것도 말해주지 않는다. 왜'shared_ptr'는 단순히'operator *()'를 오버로드하지 않고'p-> m'을'(* p) .m'으로 다시 쓰게하는 대신'operator->()'를 오버로드해야합니까? 이것은 일관성의 명백한 이점을 가지고 있습니다 - 당신은 어느 구문을 사용해도 동일한 결과를 얻을 수 있습니다. 이것은 모두가 기대하는 것입니다. 그런데 왜 이렇게하지 않았습니까? –

+0

@j_random_hacker +1 정확히 내 요점이야! – fredoverflow

3

일반적인 C++ 연산자의 의미를 완전히 바꾸면 Boost Karma의 줄을 따라 C++ 내에서 DSL을 만들 때 사용할 수 있습니다 (라이브러리에 ->이 오버로드되지는 않지만). 그게 좋은 생각인지는 논쟁의 여지가 있습니다.

+0

+1 그 이유 그 자체에 대한 +1,하지만 그건 나에게 끔찍한 생각처럼 느껴지는 ... 세계의 상태를 변경 copy ctor 작성만큼 나쁜 (때로는 컴파일러가 그것을 호출하거나 선택할 수 있기 때문에). –

1

일반 포인터는 p->m(*p).m을 제공하며 p->m은 훨씬 더 일반적입니다. 그 중 하나만 과부하하도록 허용 한 경우 기본 유형과 일치하지 않습니다. 왜 컴파일러가 다시 작성하게하지 않는가에 대한 간단한 대답은 operator *가 T *를 반환하는 것을 원하지 않기 때문입니다. 여기서 operator *는 T &을 반환합니다. 이들을 개별적으로 과부하하도록 허용하면 반드시 생각할 수없는 조합이 허용됩니다. 그러나 우리가 현재 그것을 바꿀 어떠한 이유도 생각할 수 없기 때문에 그것을 거부하는 것은 어리석은 일입니다. int128 클래스와 overload 연산자 + =를 사용하면 원하는 경우 누적 값을 대신 사용할 수 있습니다.

+0

나는 단지 무언가를 금하는 생각에 동의한다. 왜냐하면 여러분은 그것이 나쁘다는 좋은 이유를 생각할 수 없기 때문입니다. 그렇기 때문에'->'의 오버로딩을 지원하는 어떤 인자도 C++이 허용하지 않는'.'의 오버로딩을 지원할 것이라고 생각합니다 네가 과부하 걸. –

+0

반드시 그렇지는 않습니다. 사람들이 항상 기본 클래스에 계속 액세스 할 수 있도록 적어도 하나의 연산자는 과부하가 불가능한 상태 여야합니다. – Puppy

+0

미안하다 - 기본 클래스에 항상 액세스 할 수 있어야하는 이유는 무엇입니까? 게다가'->'가'.'보다 오버로드에 더 적합한 이유는 분명하지 않습니다. –