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';
}
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);
}