I'm trying to use C++20 concepts, to start familiarizing with them.
I feel pretty comfortable with easy concepts, for example with the standard concept movable
I can write something like this (in all examples I suppose I'm using namespace std
and I included <concepts>
and any other header needed):
template<movable T>
int foo (T obj);
And be sure that when this function is called the passed object obj
can be moved.
I can write this even in a longer form:
template<typename T>
requires movable<T>
int foo (T obj);
And the result would be the same (I think).
But now let's look at another concept such as same_as
. same_as
takes 2 templates parameter (the 2 types to compare), so I can write:
template<typename T>
requires same_as<T, string>
int bar (T obj);
And now T is string
. But How can I write it in the shorter form? I tried, and I can write this (as I intuitively expected):
template<same_as<string> T>
int bar (T obj);
But what is the formal rule behind this form?
Is the name (T
) of the function template parameter, entered as first argument of the concept template? Or maybe as last? I don't know, there is very little information about this topic. I mean, in this example it is irrelevant, because same_as<A, B>
is semantically equivalent to same_as<B, A>
, but there are for sure cases where the order matters.
I know there are questions with similiar titles, such as this one, but it asks a different thing.
These are the resources I tried to get information from, but failed: cppReference, cppModernes, open-std (I browsed years 2018, 2019 and 2020) and this post.
C++ Templates: Templates with Multiple Parameters | C++ Tutorials for Beginners #65.
When argument is more than one, they are separated by commas. Test test1 (1.23, 123); tells the compiler that the first argument is of type float and another one is int type. During creation of objects, constructor is called and values are received by template arguments.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Function Templates with Multiple Parameters You can also use multiple parameters in your function template. The above syntax will accept any number of arguments of different types. Above, we used two generic types such as A and B in the template function.
But what is the formal rule behind this form?
The rule (that you correctly guessed your way into) is described in [temp.param]/4:
A type-constraint
Q
that designates a conceptC
can be used to constrain a contextually-determined type or template type parameter packT
with a constraint-expressionE
defined as follows. IfQ
is of the formC<A1, ⋯, An>
, then letE′
beC<T, A1, ⋯, An>
. Otherwise, letE′
beC<T>
. IfT
is not a pack, thenE
isE′
, otherwiseE
is(E′ && ...)
. This constraint-expressionE
is called the immediately-declared constraint ofQ
forT
. The concept designated by a type-constraint shall be a type concept ([temp.concept]).
With examples in the subsequent paragraph:
A type-parameter that starts with a type-constraint introduces the immediately-declared constraint of the type-constraint for the parameter. [ Example:
template<typename T> concept C1 = true; template<typename... Ts> concept C2 = true; template<typename T, typename U> concept C3 = true; template<C1 T> struct s1; // associates C1<T> template<C1... T> struct s2; // associates (C1<T> && ...) template<C2... T> struct s3; // associates (C2<T> && ...) template<C3<int> T> struct s4; // associates C3<T, int> template<C3<int>... T> struct s5; // associates (C3<T, int> && ...)
— end example ]
You can also think of template <C T>
as being shorthand for template <C<> T>
, and then the type parameter T
just always slots into the first argument of the concept.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With