c++20 concept check for function being declared const

Viewed 346

I want to test out the new concepts feature in c++20 and I was wondering if I can create a concept that checks for the existence of a function that is declared const.
I want the check to fail if the function exists with the right type but isn't const. I couldn't find anything relevant here: https://en.cppreference.com/w/cpp/concepts

I have this

template <typename T>
concept hasToString = requires (T val) {
    { val.toString() } /* const here gives error */ -> std::same_as<std::string>;
};

void f(hasToString auto bar)
{
    std::cout << bar.toString();
}
2 Answers

You can make the parameter const:

template <typename T>
concept hasToString = requires (T const val) {
    { val.toString() } -> std::same_as<std::string>;
};

Concepts check usage patterns, and so if what you want to check is calling a member function on a const object, you need to construct that scenario.


Note that this depends on what you want to happen if T happens to be a reference type. If you want this to work:

void f(hasToString auto&& bar)

Then T might be a reference type, and if you still want it really be const, then you need to turn a type like T& into T const. The long-way of writing that is:

template <typename T>
concept hasToString = requires (std::remove_reference_t<T> const val) {
    { val.toString() } -> std::same_as<std::string>;
};

But if you do this enough times, you could consider adding an alias template to handle that.

You can always check the expression is well-formed when applied to a const object argument.

template <typename T>
concept hasToString = requires (T val) {
    { std::as_const(val).toString() } -> std::same_as<std::string>;
};

or

template <typename T>
concept hasToString = requires (T val, T const cval) {
    { cval.toString() } -> std::same_as<std::string>;
};

Adding an extra object parameter is probably more inline with how abstract concept requirements are defined (well, if your requires-expression checks for more than one requirement). You can have as many parameters as you want in the require-expression's parameter list.

Related