A lambda with a template parameter list using C++20 requires clauses is not usable in a constant expression

Viewed 185

In the template function f, I define a lambda with a template parameter list which can use if constexpr to detect whether the type U is a std::vector:

template <typename T>
void f(T t) {
  auto g = []<typename U>(U u) {
    if constexpr (requires { std::same_as<U, std::vector<typename U::value_type>>; }) {
      if constexpr (std::same_as<U, std::vector<typename U::value_type>>) {
        // deal with std::vector<U::value_type>
      }
    }
    else {
      // deal with other type
    }
  };
  g(t);
}

But when I call the f in the main function:

int main()
{
  f(std::vector<int>{});
}

The GCC-10 compiler occurs an error saying that:

<source>:19:23:   required from here
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/concepts:57:15:   required for the satisfaction of '__same_as<_Tp, _Up>' [with _Tp = U; _Up = std::vector<typename U::value_type, std::allocator<typename U::value_type> >]
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/concepts:57:32: error: the value of 'std::is_same_v<U, std::vector<typename U::value_type, std::allocator<typename U::value_type> > >' is not usable in a constant expression
   57 |       concept __same_as = std::is_same_v<_Tp, _Up>;
      |                           ~~~~~^~~~~~~~~~~~~~~~~~~
In file included from /opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/concepts:44,
                 from <source>:1:
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/type_traits:3182:25: note: 'std::is_same_v<U, std::vector<typename U::value_type, std::allocator<typename U::value_type> > >' used in its own initializer
 3182 |   inline constexpr bool is_same_v = _GLIBCXX_BUILTIN_IS_SAME_AS(_Tp, _Up);
      |                         ^~~~~~~~~ 

This seems weird to me since the type U can be deduced in the compiler time. Is this a bug for GCC-10? or there some issue in the above code?

Weirder, when I change the origin requires clauses into nested requirements:

template <typename T>
void f(T t) {
  auto g = []<typename U>(U u) {
    if constexpr (requires { requires std::same_as<U, std::vector<typename U::value_type>>; }) {
      // deal with std::vector<U::value_type>
    }
    else {
      // deal with other type
    }
  };
  g(t);
}

The GCC occurs an internal compiler error:

<source>:19:23:   required from here
<source>:7:39: internal compiler error: in dependent_type_p, at cp/pt.c:26400
    7 |     if constexpr (requires { requires std::same_as<U, std::vector<typename U::value_type>>; }) {
      |                              ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please submit a full bug report,
with preprocessed source if appropriate.

and when I change the template function f into a non-template function:

void f(std::vector<int> t) {
  auto g = []<typename U>(U u) {
    if constexpr (requires { requires std::same_as<U, std::vector<typename U::value_type>>; }) {
      // deal with std::vector<U::value_type>
    }
    else {
      // deal with other type
    }
  };
  g(t);
}

It will compile correctly, and all three examples do compile with Clang.

0 Answers
Related