Concepts can be used to put a constraint on types as template parameters like the example below:
template<typename t, int v>
concept the_concept1 = sizeof(t) > v;
template<int v, the_concept1<v> t>
struct some_struct1{};
I am trying to use a similar method with values like the example below:
template<int v1, int v2>
concept the_concept2 = v1 > v2;
template<int v1, the_concept2<v1> v2>
struct some_struct2{};
But with G++ 10 I am getting the following error message:
error: ‘the_concept2’ does not constrain a type
So I was wondering if concepts can be used to put a constraint on values? If so then how should I do it?
Edit: My final goal is to use the concept in declaration of a template structure with variadic template parameters like:
template<typename t, std::size_t ... v>
struct the_struct;
And I need a concept to check if every v
is less than sizeof(t)
.
Concepts are a revolutionary approach for writing templates! They allow you to put constraints on template parameters that improve the readability of code, speed up compilation time, and give better error messages. Read on and learn how to use them in your code!
A constraint is a requirement that types used as type arguments must satisfy. For example, a constraint might be that the type argument must implement a certain interface or inherit from a specific class. Constraints are optional; not specifying a constraint on a parameter is equivalent to using a Object constraint.
Writing conceptsConstraint expression can contain constexpr boolean expressions, conjunction/disjunction of other concepts and requires blocks. So for our previous example, we could construct a boolean expression using C++11 type traits or construct a compound concept from C++20 standard library concepts.
If you want to use a concept as a named type constraint on a template parameter, as in your example, the concept needs to apply to a type template parameter.
You can still define concepts that apply only to e.g. non-type template parameters, however, as long as you use it in a context which allows these; e.g. using a requires-clause:
template<int v1, int v2>
concept the_concept2 = v1 > v2;
template<int v1, int v2> requires the_concept2<v1, v2>
struct some_struct2{};
using valid = some_struct2<42, 41>;
//using invalid = some_struct2<42, 42>; // constraints not satisfied
Another example applied on a function template or a member function of a class template:
template<int v1, int v2>
concept the_concept2 = v1 > v2;
template <int a, int b>
void bar() requires the_concept2<a, b> {}
template <int a, int b>
struct Foo {
static void bar() requires the_concept2<a, b> {}
};
int main() {
bar<2, 1>();
Foo<2, 1>::bar();
//bar<2, 2>(); // candidate template ignored: constraints not satisfied
//Foo<2, 2>::bar(); // invalid reference to function 'bar': constraints not satisfied
}
The following OP edit (which basically asks an entirely different question)
Edit: My final goal is to use the concept in declaration of a template structure with variadic template parameters like:
template<typename t, std::size_t ... v> struct the_struct;
And I need a concept to check if every
v
is less thansizeof(t)
.
can be achieved by specifying the concept itself to apply for variadic non-type template parameters that are expanded in the sizeof(T) > v
check using parameter pack expansion:
#include <cstddef>
#include <cstdint>
template<typename T, std::size_t... v>
concept the_concept1 = (... && (sizeof(T) > v));
template<typename T, std::size_t... vs> requires the_concept1<T, vs...>
struct the_struct;
using TypeOfSize4Bytes = uint32_t;
using valid = the_struct<TypeOfSize4Bytes, 1, 3, 2, 1>;
using also_valid = the_struct<TypeOfSize4Bytes>;
//using invalid = the_struct<TypeOfSize4Bytes, 1, 2, 4>; // error: constraints not satisfied
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