DEV Community

Haris
Haris

Posted on

Concepts In C++ 20

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Now let's use AlwaysTrue in our templated function

template<typename T> requires AlwaysTrue<T>
void printSomething(T value)
{
    std::cout << value << std::endl;
}
Enter fullscreen mode Exit fullscreen mode

In our main driver function:
Since the concept is always true we can pass in pretty much anything.

printSomething(10);
printSomethingAutoVer("Hello World!");
Enter fullscreen mode Exit fullscreen mode

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>;
Enter fullscreen mode Exit fullscreen mode

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);
};
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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)