首页 > 解决方案 > T 是否必须是完整的类型才能在 `std::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;
}

在 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;
                               ~~~^

标签: c++language-lawyerincomplete-typedeclval

解决方案


错误的来源不是std::declval,而是类成员访问不完整。

在2.5 年前合并CWG1836 的决议之前,该标准要求类在类成员访问表达式 ( ) 中是完整的。[expr.ref]/2 在 C++11 中E1.E2

对于第一个选项(点),第一个表达式应具有完整的类类型。

[expr.ref]/2 在 C++17 中

对于第一个选项(点),第一个表达式应是具有完整类类型的泛左值。

alias-declaration而一个类在其自身内部并不被认为是完整的member-specification
C++17 中的 [class.mem]/6

}class-specifier结束时,类被视为完全定义的对象类型([basic.types])(或完整类型)。在类member-specification中,类在函数体、默认参数、noexcept-specifier和默认成员初始值设定项(包括嵌套类中的此类内容)中被认为是完整的。否则,它在其自己的类成员规范中被视为不完整。


推荐阅读