I have the function GetThing as follows:
auto GetThing(size_t index, auto&& l1)
{
    return l1;
}
auto GetThing(size_t index, auto&& l1, auto&&... rest)
{
    if (index == 0)
        return l1;
    return GetThing(index - 1, rest...);
}
I want it to be able to work with different lambdas too while being able to handle other types (meaning non-lambdas, non functions, like int, and ...) , such as
std::cout << GetThing(1, 2, 3, 4);   //works, return 3
std::cout << GetThing(1, [] {return 0; }, 
    [] {return 1; }, [] {return 2; }, 
    [] {return 3; } )();             //nope
But the problem here being the lambdas are different type, therefore the recursive function will deduced to incompatible return type, so I seems to have to use std::function like this, but it's ugly.
std::cout << GetThing(1, std::function{ [] {return 0; } }, std::function{ [] {return 1; } }, std::function{ [] {return 2; } }, std::function{ [] {return 3; } })();//works
Any possible way to get around this, for example if there is an overloaded operator() then it automatically enforce the type to be std::function?
EDIT: I am aware of capture-less lambdas can be converted to a function pointer, but how to deduce it that way without std::decay in the template? Because I still want to to be handle other types as references
EDIT2: I receive a few answers utilizing std::variant, and am thinking of that, besides lambda, the parameter types shall be the same, eg. std::variant<int, int, int>. It maybe possible to add overload to GetThing, such that whenstd::variant is holding the same types, it return the thing of that type, otherwise (which is the case of receiving lambdas), returns a std::function
You may store your functions in an array of variants. This comes with some overhead of course. But this enables to have functions also using captured vars.
This enable to pick a function from such function collection and execute it with given parms as follows:
template < typename ARR_T >
struct Collect
{
    template < typename ... T > 
    Collect( T&&...args  ): arr{std::forward<T>(args)...}{}
    ARR_T arr;
    using VARIANT_T = ARR_T::value_type;
    VARIANT_T& operator[]( size_t index) { return arr[index]; }
};
template < typename ... T > 
Collect( T&& ... args ) -> Collect< std::array< std::variant<T... >, sizeof...(T) >>; 
template < typename C, typename ... PARMS >
auto GetThing( size_t index, C&& c, PARMS&&... parms ) 
{
    return std::visit( [ &parms...]( auto&& func)
                      {
                          return func(std::forward<PARMS>(parms)...);
                      }, c[index]);
}
int main()
{
    std::cout << GetThing( 2, Collect(  []( int, double) {return 0; }, []( int, double) {return 1; }, []( int, double) {return 2; }, []( int, double) {return 3; }), 1,5.6)<< std::endl;
    int y = 8;
    double d = 9.99;
    std::cout << GetThing( 0, Collect(  [y,d]( int, double) {return d*y; }, []( int, double) {return 1.; }, []( int, double) {return 2.; }, []( int, double) {return 3.; }), 1,5.6)<< std::endl;
}
In this case GetThing also take the function parameters for calling the lambda, because the call is using std::visit. If you "only" want to pick the function, you will get the std::variant if you like and can call the function your self.
    auto func = Collect(  []( int i, double d) {return d+i; }, []( int i, double d) {return d*i; }, []( int i, double d) {return d-i; } )[2];
    std::cout << std::visit( []( auto&& f) { return f( 9, 7.77 ); }, func ) << std::endl;
}
                        You can return a std::variant that contains all input types:
template <typename... Args>
std::variant<std::decay_t<Args>...>
GetThing(std::size_t index, Args&&... args)
{ 
  return [index, t=std::forward_as_tuple(std::forward<Args>(args)...)] 
    <std::size_t... Is>(std::index_sequence<Is...>) { 
    return std::array{ +[](const std::tuple<Args&&...>& t) { 
      return std::variant<std::decay_t<Args>...>{ 
        std::in_place_index<Is>, std::get<Is>(t)}; 
      } ... 
    }[index](t); 
  }(std::index_sequence_for<Args...>{}); 
}
Then you need std::visit to visit your returned value:
for (std::size_t index = 0; index < 4; index++)
  std::visit(
    [](auto&& f) { std::cout << f() << " "; }, 
    GetThing(index, []{return 0;}, []{return 1;}, []{return 2;}, []{return 3;})
  );
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With