c++c++20requires-expression

Are requires expressions allowed to "capture" variables of the enclosing scope?


In the following example, the function arguments are used to test with a requires expression whether an expression using them is well formed. The requires expression takes no arguments; it uses the variables in the function scope directly:

#include <cstddef>
#include <vector>

template<typename T>
void Resize(T &v, std::size_t const n)
{
  if constexpr (requires { v.resize(n); })
    v.resize(n);
}

template<typename T>
void Eziser(T &v, std::size_t const n)
{
  if constexpr (requires { v.eziser(n); })
    v.eziser(n);
}

int main()
{
  std::vector<int> v;

  Resize(v, 10u);
  Eziser(v, 10u);
}

The above code compiles with the Clang concepts branch. However, GCC10 only accepts the call to Resize. GCC9 ICEs. Is Clang right at accepting it?


Solution

  • Yes, a requires-expression can use anything that’s in scope. It needs only the type of anything it names, after all, except in a nested-requirement or other constant expression. That’s true of surrounding declarations just as much as of its own (formal) parameters.

    C++20 explicitly mentioned this in [expr.prim.req]/5:

    The requirement-body contains a sequence of requirements. These requirements may refer to local parameters, template parameters, and any other declarations visible from the enclosing context.

    This, however, was merely a restatement of general rules, so has since been removed.