[c++] `std :: declval <T>`에서 사용하기 위해 T는 완전한 타입이어야합니까?

이 예제를 고려하십시오 ( here ).

#include <type_traits>
#include <iostream>
template <typename U>
struct A {
};

struct B {
   template <typename F = int>
   A<F> f() { return A<F>{}; }

   using default_return_type = decltype(std::declval<B>().f());
};

int main()
{
    B::default_return_type x{};
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
}

그것은 gcc9.2에 오류없이 컴파일 에 대한 불평 10.0.0하지만 gcc7.2와 연타 B완료되지 않는. 클랜 오류는 다음과 같습니다.

prog.cc:11:58: error: member access into incomplete type 'B'
   using default_return_type = decltype(std::declval<B>().f());
                                                         ^
prog.cc:7:8: note: definition of 'B' is not complete until the closing '}'
struct B {
       ^
prog.cc:16:8: error: no type named 'default_return_type' in 'B'
    B::default_return_type x{};
    ~~~^
prog.cc:17:35: error: no member named 'default_return_type' in 'B'
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
                               ~~~^



답변

오류의 원인은 std::declval아니지만 완료되지 않은 클래스 멤버 액세스입니다.

CWG1836 의 해결책이 2.5 년 전에 합병 될 때까지, 표준은 클래스 멤버 액세스 식 ( E1.E2) 에서 클래스를 완료해야했습니다 .
C ++ 11의 [expr.ref] / 2 :

첫 번째 옵션 (도트)의 경우 첫 번째 표현식은 완전한 클래스 유형을 가져야합니다.

C ++ 17의 [expr.ref] / 2 :

첫 번째 옵션 (도트)의 경우 첫 번째 표현식은 완전한 클래스 유형을 가진 glvalue 여야합니다.

그리고 수업 alias-declaration자체 는 완전한 것으로 간주되지 않습니다 member-specification.
C ++ 17의 [class.mem] / 6 :

클래스는 닫을 때 완전히 정의 된 객체 유형 ([basic.types]) (또는 완전한 유형)으로 간주됩니다 }클래스 지정자 . 클래스 멤버 지정 내에서 클래스 는 함수 본문, 기본 인수, noexcept-specifier 및 기본 멤버 이니셜 라이저 (중첩 클래스의 항목 포함) 내에서 완료된 것으로 간주됩니다 . 그렇지 않으면 자체 클래스 멤버 지정 내에서 불완전한 것으로 간주됩니다 .


답변

에서 [declval] :

비고 :의 템플릿 매개 변수 Tdeclval불완전한 유형일 수 있습니다.

이 문구는 C ++ 11부터 존재하므로 컴파일러가 이전 표준을 따르는 것은 불가능합니다.


답변