A concept is just a true of false statement, it is like a predicate that returns true or false, there are a number of built in concepts as well.
Example
Let's have two templated functions for isEqual one would be integer specialization and other will be float, for this we will be using built in concepts.
template<typename T> requires std::integral<T>
bool isEqual(T valueA, T valueB)
{
std::cout << "Calling the integral version\n";
return valueA == valueB;
}
template<typename T> requires std::floating_point<T>
bool isEqual(T valueA, T valueB)
{
std::cout << "Calling the float version\n";
return std::fabs(valueA - valueB) < 0.0001f;
}
and inside our main driver function we can call these:
std::cout << std::boolalpha << isEqual(1, 1) << std::endl;
// This will work as we have a specialization
std::cout << std::boolalpha << isEqual(1.0f, 5.0f) << std::endl;
Lets Make a Custom Concept
Our concept is going to be very simple, as mentioned above concepts are just predicates that return a boolean so we are going to hard code ours to always return true.
template<typename T>
concept AlwaysTrue = true;
Now let's use AlwaysTrue in our templated function
template<typename T> requires AlwaysTrue<T>
void printSomething(T value)
{
std::cout << value << std::endl;
}
In our main driver function:
Since the concept is always true we can pass in pretty much anything.
printSomething(10);
printSomethingAutoVer("Hello World!");
You can also combine different concepts using || operator, so we can make a specialization that takes both integers and floating point values
template<typename T>
concept IsFloatORInt = std::floating_point<T> || std::integral<T>;
Template Specialization Only for Types that have a Push-Back
We want to have a template that only compiles for types that have a push back function.
template<typename T>
concept HasPushback = requires(T container, T::value_type valueType) {
container.push_back(valueType);
};
Since we need to know that we can push a value in the container we are also going to be needing to know the value type that resides in our container, this can be extracted using the value_type, Now let's make our templated function:
template<typename T> requires HasPushback<T>
void addIntToContainer(T& container, int integer)
{
container.push_back(integer);
}
Concepts are really powerful you can now use the same ideas to do things like make template specializations for types that have a size available at compile time, different specializations for small and big data etc.
Top comments (0)