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


11

이 예제를 고려하십시오 ( 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;
                               ~~~^

1
질문 제목이 오류와 일치하지 않습니까? GCC가에 대해 불평하는 것처럼 보입니다 .f(). 말이 되네요. 불완전한 유형 B에는 멤버가 없습니다 f.
MSalters

@MSalters 나는 똑같은 생각을했지만 실제 문제는 무엇입니까? std::declval유형이 완료되었는지 여부에 관계없이 인스턴스를 가져 오면 더 이상 문제가되지 않는다고 가정합니다 (내가 틀린 것 같습니다)
idclev 463035818

[expr.ref] / 2 (C ++ 11)는 클래스 멤버 액세스에 대해 말합니다. "첫 번째 옵션 (도트)의 경우 첫 번째 표현식은 완전한 클래스 유형을 가져야 합니다. " 그리고에서 B완료된 것으로 간주되지도 않습니다 alias-declaration.
언어 변호사


1
@LanguageLawyer 좋아, 나는 내 해석이 꺼져 있고 c ++ 11 이후로 변경된 것이있는 것 같습니다. 답을 쓰시겠습니까?
idclev 463035818

답변:


9

오류의 원인은 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 및 기본 멤버 이니셜 라이저 (중첩 클래스의 항목 포함) 내에서 완료된 것으로 간주됩니다 . 그렇지 않으면 자체 클래스 멤버 지정 내에서 불완전한 것으로 간주됩니다 .


8

에서 [declval] :

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

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


대단하네요. 제가 바라는 바입니다. gcc가 고정 된
것처럼 보이며

@ formerlyknownas_463035818 : 첫 번째 생각은 T절대적으로 완전한 유형이어야 한다는 것이 었습니다 . 기쁘다 나는 표준을 확인했다.
AndyG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.