Requires clause with pure abstract class type parameter?

Consider the following simple concept:

template <typename T>
concept C = requires(T a) { a.f(); };

What should happens if we take an abstract class type as the requires expressions‘s argument?

struct B { virtual void f() = 0; };

static_assert(C<B>);

gcc-trunk and msvc-trunk pass the assertion, however, clang-trunk, gcc-10.2, and msvc v19.24 reject the assertion.

What does the standard say?

Answer

GCC-trunk and MSVC-trunk are correct. The restrictions on the use of abstract types have changed between C++17 and C++20 thanks to P0929. Consequently, even ordinary function declarations with abstract parameter types are now allowed:

void foo(B b);  // ill-formed in C++17, well-formed in C++20
void foo(B b) { /* ... */ }  // still ill-formed in C++20

The wording “An abstract class shall not be used as a parameter type…” (C++17 [class.abstract]/3) was removed. In C++20, it is ill-formed for a function to have an abstract parameter type only if the function is being called ([expr.call]/7) or defined ([dcl.fct.def.general]/2). Furthermore, a parameter-declaration found in a requires-parameter-list is not a definition, just like how a parameter-declaration found in a non-defining declaration of a function is not a definition ([basic.def]/2.8).

Leave a Reply

Your email address will not be published. Required fields are marked *