Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between using a Concept directly instead of `typename`, versus using the `requires` keyword? Or is it just a matter of style?

I'm trying to wrap my head around concepts in C++20. Consider the following (very simple) concept:

template <typename T>
concept Float = requires
{
    std::floating_point<T>;
};

I can write a templated class using this concept in 2 ways:

template <Float T>
class MyClass {
public:
    MyClass(T val) : value{ val } {};
private:
    T value;
};

Or I can do

template <typename T> requires Float<T>
class MyClass {
public:
    MyClass(T val) : value{ val } {};
private:
    T value;
};

In this particular example, these behave exactly the same. Is this always the case though? Are there situations where it is easier to express some constraint using the template <...> requires ... syntax? Or is this merely a style preference/convention?

The only thing I can think of right now is that using the template <...> requires ... syntax may allow you represent relational constraints between multiple template arguments, where as the template <CONCEPT T> syntax only allows you to represent a constraint on a single argument?

Any guidance would be much appreciated.

like image 602
Chris Gnam Avatar asked Dec 31 '25 06:12

Chris Gnam


2 Answers

There is no difference between:

template <Float T>

and

template <typename T> requires Float<T>

They mean the same thing. If you declare a template and then define it later, you have to use the same syntax in both places - but both syntaxes do mean the same thing.

It's purely a matter of preference. The type-constraint syntax is more limited (can only be used to constrain a type) but can be more readable.

Note that the type-constraint syntax can express multi-type constraints. For instance the typical ranges pattern of:

template <typename I, typename S>
    requires input_iterator<I>
         and sentinel_for<S, I>
void algo(I, S);

can be written with the shorthand:

template <input_iterator I, sentinel_for<I> S>
void algo(I, S);
like image 69
Barry Avatar answered Jan 03 '26 10:01

Barry


Using concept names in place of typenames is always a shorthand for something you could do in long-form. However, there are some circumstances where the long-form equivalent is more unwieldy.

For example:

template <Concept auto value>
class foo {...};

//becomes

template <auto value> requires Concept<decltype(value)>
class foo {...};
like image 30
Nicol Bolas Avatar answered Jan 03 '26 10:01

Nicol Bolas