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

Why does GCC succeeds on a constraint with std::tuple_size::value, but fails on one with std::tuple_size_v?

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

#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
/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;
      |                                                             ^~~~~

我预计根据 https://en.cppreference.com/w/cpp/language/constraints

所有三个都被评估为 false

Satisfaction of an atomic constraint is checked by substituting the parameter mapping and template arguments into the expression E. If the substitution results in an invalid type or expression, the constraint is not satisfied.

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

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 是不受约束的 class 模板,因此可以轻松满足。