为什么 GCC 在使用 std::tuple_size::value 的约束上成功,但在使用 std::tuple_size_v 的约束上失败?

Ser*_*riy 2 c++ c++-concepts c++20

在下面的代码中,为什么第二个和第三个概念会产生编译错误?

#include <tuple>

template <class P>
concept IsPair1 = std::tuple_size<P>::value == 2;

template <class P>
concept IsPair2 = std::tuple_size_v<P> == 2;

template <class P>
concept IsPair3 = requires { typename std::tuple_size<P>; } && std::tuple_size_v<P> == 2;

constexpr bool intIsPair1 = IsPair1<int>;  // OK, false

constexpr bool intIsPair2 = IsPair2<int>;  // error: incomplete type 'std::tuple_size<int>' used in nested name specifier

constexpr bool intIsPair3 = IsPair3<int>;  // error: incomplete type 'std::tuple_size<int>' used in nested name specifier
Run Code Online (Sandbox Code Playgroud)
/usr/local/Cellar/gcc/11.1.0_1/include/c++/11.1.0/tuple:1334:61: error: incomplete type 'std::tuple_size<int>' used in nested name specifier
 1334 |     inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value;
      |                                                             ^~~~~
Run Code Online (Sandbox Code Playgroud)

我预计根据https://en.cppreference.com/w/cpp/language/constraints所有三个都会被评估为 false ,

通过将参数映射和模板实参替换到表达式 E 中来检查原子约束的满足情况。如果替换导致无效类型或表达式,则不满足约束。

T.C*_*.C. 6

变量模板的初始值设定项不在直接上下文中,因此那里的任何错误都会导致硬错误而不是替换失败。

std::tuple_size<P>::value == 2之所以有效,是因为尝试命名value不完整类型的成员是在直接上下文中。

requires { typename std::tuple_size<P>; } && std::tuple_size_v<P> == 2不起作用,因为第一部分只检查它std::tuple_size<P>是一个类型,由于它tuple_size是一个不受约束的类模板,因此很容易满足。