c++templatesc++20c++-conceptstrailing-return-type

How to apply a concept to a trailing return type


Here is some basic example:

template <typename T, typename Callable>
constexpr auto foo(T arg, Callable&& make)
    -> decltype(make(std::declval<T>())) {
    return make(arg);
}

Is it possible to apply a constraint to the trailing return type and how?

Now what I'm doing is:

template <typename T, typename Callable,std::integral Returned = decltype(std::declval<Callable>()(std::declval<T>()))>
constexpr auto bar(T arg, Callable&& make){
    return make(arg);
}

bar can only be called with callable returning an integral value, which I find a bit convoluted and hard to read (probably a matter of taste though).

This is a full example:

#include <concepts>
#include <iostream>
#include <utility>

template <typename T, typename Callable>
constexpr auto foo(T arg, Callable&& make)
    -> decltype(make(std::declval<T>())) {
    return make(arg);
}

template <typename T, typename Callable,
          std::integral Returned =
              decltype(std::declval<Callable>()(std::declval<T>()))>
constexpr auto bar(T arg, Callable&& make) {
    return make(arg);
}

double make_double(int i) { return 3.14 * i; }
int make_int(int i) { return i; }

int main() {
    std::cout << foo(1, make_double) << '\n';
    std::cout << foo(1, make_int) << '\n';
    // constraint not fullfilled
    // std::cout << bar(1, make_double) << '\n';
    std::cout << bar(1, make_int) << '\n';
}

LIVE


Solution

  • Just use a requires-clause with a requires-expression.

    template <typename T, typename Callable>
    constexpr auto bar(T arg, Callable&& make) 
        requires requires { { make(arg) } -> std::integral; }
    {
        return make(arg);
    }