Suppose I have a routine that receives a callable Lambda as parameter, and this Lambda is allowed to have 2 signatures: it can be called providing an int or 2 ints.
The problem is: how to determine the result type of this Lambda.
The following code illustrates the problem
#include <iostream>
#include <type_traits>
template <class Lambda>
auto f(Lambda&& f)
{
using result_type = std::conditional_t<std::is_invocable_v<Lambda, int>, std::invoke_result_t<Lambda, int>, std::invoke_result_t<Lambda, int, int>>;
result_type res;
if constexpr (std::is_invocable_v<Lambda, int>) {
res = f(3);
}
else {
res = f(3, 3);
}
return res;
}
int main()
{
std::cout << f([](int x) -> int { return x; }) << std::endl;
std::cout << f([](int x, int y) -> int { return x * y; }) << std::endl;
return 0;
}
Check it Live on Coliru.
The code does not compiles because, inside std::conditional_t
, both the 2nd and 3rd template parameters must be defined, and here clearly only one exists.
I can think about writing a traits that serves to this problem, say exploiting template specialization. Something like
template <class F, bool T>
struct helper;
template <class F>
struct helper<F, true> {
using type = std::invoke_result_t<F, int>;
};
template <class F>
struct helper<F, false> {
using type = std::invoke_result_t<F, int, int>;
};
But before reinventing the wheel: is there a simpler compact solution using the std library? I am interested in a c++17 solution.
From your code, you just have to "delay" evaluation:
using result_type =
std::conditional_t<std::is_invocable_v<Lambda, int>,
std::invoke_result<Lambda, int>,
std::invoke_result<Lambda, int, int>>::type;