Nice programing

GCC는 operator ++ ()와 operator ++ (int)를 구분할 수 없습니다.

nicepro 2020. 12. 5. 10:38
반응형

GCC는 operator ++ ()와 operator ++ (int)를 구분할 수 없습니다.


template <typename CRTP>
struct Pre {
    CRTP & operator++();
};

template <typename CRTP>
struct Post {
    CRTP operator++(int);
};

struct Derived
    : Pre<Derived>
    , Post<Derived>
{};

int main() {
    Derived d;
    d++;
    ++d;
}

GCC에서 다음 오류가 발생합니다.

<source>: In function 'int main()':
<source>:18:10: error: request for member 'operator++' is ambiguous
        d++;
        ^~
<source>:8:14: note: candidates are: CRTP Post<CRTP>::operator++(int) [with CRTP = Derived]
        CRTP operator++(int);
            ^~~~~~~~
<source>:3:16: note:                 CRTP& Pre<CRTP>::operator++() [with CRTP = Derived]
        CRTP & operator++();
                ^~~~~~~~
<source>:19:11: error: request for member 'operator++' is ambiguous
        ++d;
        ^
<source>:8:14: note: candidates are: CRTP Post<CRTP>::operator++(int) [with CRTP = Derived]
        CRTP operator++(int);
            ^~~~~~~~
<source>:3:16: note:                 CRTP& Pre<CRTP>::operator++() [with CRTP = Derived]
        CRTP & operator++();
                ^~~~~~~~

사전 감소 및 사후 감소 연산자는 유사한 오류를 발생시킵니다. Clang에는 그러한 오류가 없습니다. 무엇이 잘못되었거나이 문제를 해결하는 방법에 대한 아이디어가 있습니까?


이름 조회가 먼저 발생해야합니다. 이 경우 이름 operator++.

[basic.lookup] (내 강조)

1 이름 조회 규칙은 문법이 허용하는 모든 이름 (typedef-names ([dcl.typedef]), namespace-names ([basic.namespace]) 및 class-names ([class.name]) 포함)에 균일하게 적용됩니다. 특정 규칙에 의해 논의되는 문맥에서 그러한 이름. 이름 조회는 이름의 사용을 해당 이름의 선언 ([basic.def])과 연결합니다. 이름 조회는 이름에 대한 명확한 선언을 찾습니다 ([class.member.lookup] 참조) . 이름 조회는 이름이 함수 이름 인 것을 발견하면 하나 이상의 선언을 이름과 연관시킬 수 있습니다. 선언은 오버로드 된 함수 집합 ([over.load])을 형성한다고합니다. 이름 조회가 성공한 후 오버로드 확인 ([over.match])이 발생합니다.. 액세스 규칙 (Clause [class.access])은 이름 조회 및 함수 오버로드 확인 (해당되는 경우)이 성공한 경우에만 고려됩니다. 이름 조회, 함수 오버로드 확인 (해당되는 경우) 및 액세스 검사가 성공한 후에 만 ​​식 처리에서 추가로 사용되는 이름 선언에 의해 도입 된 속성이 있습니다 (Clause [expr]).

그리고 조회가 모호하지 않은 경우에만 오버로드 해결이 진행됩니다. 이 경우 이름은 서로 다른 두 클래스의 범위에서 발견되므로 과부하 해결 이전에도 모호성이 존재합니다.

[class.member.lookup]

8 오버로드 된 함수의 이름이 모호하지 않으면 액세스 제어 전에 오버로드 해결 ([over.match])도 발생합니다. 모호성은 종종 클래스 이름으로 이름을 한정하여 해결할 수 있습니다. [ 예:

struct A {
  int f();
};

struct B {
  int f();
};

struct C : A, B {
  int f() { return A::f() + B::f(); }
};

— 최종 예]

The example pretty much summarizes the rather long lookup rules in the previous paragraphs of [class.member.lookup]. There is an ambiguity in your code. GCC is correct to report it.


As for working around this, people in comments already presented the ideas for a workaround. Add a helper CRTP class

template <class CRTP>
struct PrePost
    : Pre<CRTP>
    , Post<CRTP>
{
    using Pre<CRTP>::operator++;
    using Post<CRTP>::operator++;
};

struct Derived : PrePost<Derived> {};

The name is now found in the scope of a single class, and names both overloads. Lookup is successful, and overload resolution may proceed.

참고URL : https://stackoverflow.com/questions/54091513/gcc-cant-differentiate-between-operator-and-operatorint

반응형