태그 보관물: c++20

c++20

템플릿 클래스에서 C ++ 20 클래스 외부 정의 rhs) { return

C ++의 C ++ 20 표준까지 템플릿 클래스의 개인 멤버를 사용하는 클래스 외 연산자를 정의하려면 다음과 유사한 구문을 사용합니다.

template <typename T>
class Foo;

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs);

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);

private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

int main() {
    return 1 == Foo<int>(1) ? 0 : 1;
}

그러나 C ++ 20 이후 클래스 외부 선언을 생략하여 순방향 선언을 생략 할 수 있으므로 다음과 같이 해결할 수 있습니다.

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);
private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

Demo

이제 제 질문은 C ++ 20의 어떤 부분에서 그렇게 할 수 있습니까? 그리고 왜 이전 C ++ 표준에서 이것이 가능하지 않았습니까?


주석에서 지적했듯이 clang은 데모에 표시된이 코드를 허용하지 않으므로 실제로 gcc의 버그 일 수 있습니다.

gcc의 bugzilla에 버그 보고서 를 제출했습니다



답변

GCC에 버그가 있습니다.

<문제의 이름이 (친구, 명시 적 전문화 또는 명시 적 인스턴스화) 선언에서 선언 된 이름 인 경우에도 이름 앞에는 템플릿 이름이 항상 앞에 나타납니다 .

operator==친구 선언 의 이름 은 규정되지 않은 이름이며 템플리트에서 이름을 조회 할 수 있으므로 2 단계 이름 조회 규칙이 적용됩니다. 이와 관련 operator==하여 종속 이름이 아니므로 (함수 호출의 일부가 아니므로 ADL이 적용되지 않음) 이름이 나타나는 지점에서 조회되고 바인딩됩니다 ([temp.nondep] 단락 1 참조). 이 이름 조회에서에 대한 선언이 없으므로 예제가 잘못 구성되었습니다 operator==.

GCC가 P0846R0 으로 인해 C ++ 20 모드에서이를 수락 할 것으로 예상합니다 . 이는 operator==<T>(a, b)템플릿으로의 사전 선언 operator==이 표시 되지 않더라도 (예 🙂 템플릿에서 사용할 수 있습니다.

더 흥미로운 테스트 케이스가 있습니다.

template <typename T> struct Foo;

#ifdef WRONG_DECL
template <typename T> bool operator==(Foo<T> lhs, int); // #1
#endif

template <typename T> struct Foo {
  friend bool operator==<T>(Foo<T> lhs, float); // #2
};

template <typename T> bool operator==(Foo<T> lhs, float); // #3
Foo<int> f;

을 사용 -DWRONG_DECL하여 GCC와 Clang은이 프로그램이 잘못 작성되었다는 데 동의합니다. 템플릿 정의와 관련하여 친구 선언 # 2에 대한 정규화되지 않은 조회는 인스턴스 #의 일치하는 친구와 일치하지 않는 선언 # 1을 찾습니다 Foo<int>. 템플릿의 정규화되지 않은 조회에서 찾을 수 없으므로 선언 # 3도 고려되지 않습니다.

을 사용 -UWRONG_DECL하면 GCC (C ++ 17 및 이전 버전)와 Clang은이 프로그램이 다른 이유로 잘못 구성되어 있음에 동의합니다 operator==.

그러나 -UWRONG_DECLC ++ 20 모드의 GCC는 operator==# 2에서 정규화되지 않은 조회 가 실패한 것 (P0846R0으로 인한 것)이 정상인지 확인한 다음 템플릿 인스턴스화 컨텍스트에서 조회를 다시 실행하여 이제 # 3을 찾습니다. 템플릿에 대한 일반적인 2 단계 이름 조회 규칙 위반


답변