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.