I am failing to understand how the requires keyword works inside a nested template.
The code below can be compiled on the latest versions of MSVC and gcc (using /std:c++latest and -std=c++2a, respectively).
Is the requires simply discarded in scenarios like this? Should I not use it this way?
#include <type_traits>
template <
template < typename >
requires (false) // Should not this stop compilation?
typename Wrapper >
using Test = Wrapper < int >;
template < typename >
struct S
{
};
int main() {
Test < S > var;
return 0;
}
I think the compilers are not implementing this correctly and you are correct that it should fail to compile.
In [temp.names]/7 it says that a template-id formed from a template template parameter with constraints must satisfy these constraints if all template arguments are non-dependent.
You are giving
Wrapperonly one argument, namelyintwhich is not dependent. Therefore the compiler should check whetherWrapper<int>satisfies the constraintrequires(false)ofWrapper. This check should fail.I am not completely sure that
requires(false)specifically is not IFNDR, because there are some similar rules forbidding e.g. templates which can never be instantiated, but the compilers seem to behave the same way if a non-trivial constraint is used.Clang complains that the
requiresclause is a syntax error in that position, but I don't see any reason for that.MSVC actually handles for example the following variation using a type constraint instead of a requires-clause as expected:
but does not reject as expected if a requires-clause is used:
Interestingly Clang crashes with an ICE on the former.