C++ concepts with variadic templates

93 Views Asked by At

I've returned to c++ after many years and trying to grasp the concepts. I've written a simple test code, but I'm getting an error which I don't really understand why it is here.

template <typename T, typename U>
concept addable = requires (T a, U b)
{
    a + b;
};

template <typename T>
T test_add(T&& value)
{
    return value;
}

template <typename T, typename... Args>
auto test_add(T&& value, Args&&... rest) requires addable<T, decltype(test_add(forward<Args>(rest)...))>
{
    return value + test_add(forward<Args>(rest)...);
}

The goal is to check if there is a valid + operation on the returning expression, but when i call the function like this:

auto result = test_add(1, 3, 5);

I get following error: "no instance of overloaded function "test_add" matches the argument list".

What is wrong here?

1

There are 1 best solutions below

6
Ted Lyngmo On BEST ANSWER

It looks like you want the concept to be variadic, so you need a parameter pack and then a fold expression over the + operator:

template <class... Ts>
concept addable = requires(Ts&&... ts) { (... + ts); };
//                                        ^^^^^^^^
//                                        fold over +           

Your test_add function templates could then be replaced with one that uses the concept (with a similar fold expression):

auto test_add(addable auto&&... values) {
    return (... + std::forward<decltype(values)>(values));
}

If you want two separate function templates, you can (with the same concept as above). You mainly need to change what you put in as a requirement:

template <typename T>
decltype(auto) test_add(T&& value) {
    return std::forward<T>(value);
}

template <typename T, typename... Args>
auto test_add(T&& value, Args&&... rest)
    requires addable<T, Args...>
//           ^^^^^^^^^^^^^^^^^^^
{
    return std::forward<T>(value) + test_add(std::forward<Args>(rest)...);
}