for*_*818 12 c++ language-lawyer incomplete-type declval
考虑这个例子(来自这里):
#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;
}
Run Code Online (Sandbox Code Playgroud)
它在 gcc9.2 上编译没有错误,但 gcc7.2 和 clang 10.0.0 抱怨B不完整。Clangs 错误是:
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;
~~~^
Run Code Online (Sandbox Code Playgroud)
Lan*_*yer 10
错误的来源不是std::declval,而是不完整的类成员访问。
在2.5 年前合并CWG1836 的决议之前,标准要求类必须在类成员访问表达式 ( ) 中完成。[expr.ref]/2 在 C++11 中:E1.E2
对于第一个选项(点),第一个表达式应具有完整的类类型。
对于第一个选项(点),第一个表达式应是具有完整类类型的泛左值。
并且一个类alias-declaration在它自己的内部不被认为是完整的member-specification。
[class.mem]/6 在 C++17 中:
}在class-specifier结束时,类被认为是完全定义的对象类型([basic.types])(或完整类型)。在类成员规范中,类在函数体、默认参数、noexcept-specifier和默认成员初始值设定项(包括嵌套类中的此类内容)中被视为完整的。否则在它自己的类成员规范中被认为是不完整的。