I'm trying to understand C 20 concepts, in particular the example from here. Why is it an error if we're templatizing f with a concept that's stricter than allowed? In other words doesn't Integral4 also satisfy the Integral concept?
#include <type_traits>
#include <concepts>
template<typename T>
concept Integral = std::integral<T>;
template<typename T>
concept Integral4 = Integral<T> && sizeof(T) == 4;
template<template<Integral T1> typename T>
void f(){
}
template<typename T>
struct S1{};
template<Integral T>
struct S2{};
template<Integral4 T>
struct S3{};
void test(){
f<S1>(); // OK
f<S2>(); // OK
// error, S3 is constrained by Integral4 which is more constrained than
// f()'s Integral
f<S3>();
}
Error
<source>: In function 'void test()':
<source>:28:10: error: no matching function for call to 'f<template<class T> requires Integral4<T> struct S3>()'
28 | f<S3>();
| ~~~~~^~
<source>:11:6: note: candidate: 'template<template<class T1> class requires Integral<T1> T> void f()'
11 | void f(){
| ^
<source>:11:6: note: template argument deduction/substitution failed:
<source>:28:10: error: constraint mismatch at argument 1 in template parameter list for 'template<template<class T1> class requires Integral<T1> T> void f()'
28 | f<S3>();
| ~~~~~^~
<source>:28:10: note: expected 'template<class T1> class requires Integral<T1> T' but got 'template<class T> requires Integral4<T> struct S3'
Compiler returned: 1
CodePudding user response:
f takes a template template parameter that is constrained on Integral. This means that f is allowed to use any type T which satisfies Integral on this template.
For example, short.
S3 is a type constrained on Integral4, which subsumes Integral. This means that, while any type U which satisfies Integral4 will also satisfy Integral, the reverse is not true. There are some types T which satisfy Integral but not Integral4
short for example is Integral, but it is unlikely to satisfy Integral4.
But f has the right to use short on the template it is provided, because that's what its signature says it can do. Since S3 provided only allows a subset of the types that f's signature allows it to use, you get a compile error.
