이 예제를 고려하십시오 ( 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 :
첫 번째 옵션 (도트)의 경우 첫 번째 표현식은 완전한 클래스 유형을 가져야합니다.
첫 번째 옵션 (도트)의 경우 첫 번째 표현식은 완전한 클래스 유형을 가진 glvalue 여야합니다.
그리고 수업 alias-declaration
자체 는 완전한 것으로 간주되지 않습니다 member-specification
.
C ++ 17의 [class.mem] / 6 :
클래스는 닫을 때 완전히 정의 된 객체 유형 ([basic.types]) (또는 완전한 유형)으로 간주됩니다
}
의 클래스 지정자 . 클래스 멤버 지정 내에서 클래스 는 함수 본문, 기본 인수, noexcept-specifier 및 기본 멤버 이니셜 라이저 (중첩 클래스의 항목 포함) 내에서 완료된 것으로 간주됩니다 . 그렇지 않으면 자체 클래스 멤버 지정 내에서 불완전한 것으로 간주됩니다 .
답변
에서 [declval] :
비고 :의 템플릿 매개 변수
T
가declval
불완전한 유형일 수 있습니다.
이 문구는 C ++ 11부터 존재하므로 컴파일러가 이전 표준을 따르는 것은 불가능합니다.