函数模板接受并返回不同的 lambda

sz *_*ter 7 c++ c++20

我的功能GetThing如下:

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...);
}
Run Code Online (Sandbox Code Playgroud)

我希望它也能够处理int不同的 lambda,同时能够处理其他类型(意味着非 lambda、非函数,如和 ...),例如

std::cout << GetThing(1, 2, 3, 4);   //works, return 3
std::cout << GetThing(1, [] {return 0; }, 
    [] {return 1; }, [] {return 2; }, 
    [] {return 3; } )();             //nope
Run Code Online (Sandbox Code Playgroud)

但是这里的问题是 lambdas 是不同的类型,因此递归函数会推导出不兼容的返回类型,所以我似乎必须这样使用std::function,但它很难看。

std::cout << GetThing(1, std::function{ [] {return 0; } }, std::function{ [] {return 1; } }, std::function{ [] {return 2; } }, std::function{ [] {return 3; } })();//works
Run Code Online (Sandbox Code Playgroud)

任何可能的方法来解决这个问题,例如,如果有一个重载,operator()那么它会自动强制类型为std::function

编辑:我知道可以将无捕获的 lambdas 转换为函数指针,但是如何在没有std::decay模板的情况下以这种方式推断它?因为我还是想把其他类型作为引用处理

EDIT2:我收到了一些使用 的答案std::variant,我在想,除了 lambda 之外,参数类型应该是相同的,例如。std::variant<int, int, int>. 可能会添加重载到GetThing,这样当std::variant持有相同类型时,它返回该类型的东西,否则(这是接收 lambdas 的情况),返回一个std::function

Kla*_*aus 3

您可以将函数存储在变体数组中。当然,这会带来一些开销。但这使得函数也可以使用捕获的变量。

这使得能够从此类函数集合中选择一个函数并使用给定的参数执行它,如下所示:

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



Run Code Online (Sandbox Code Playgroud)

在这种情况下GetThing,还要获取调用 lambda 的函数参数,因为调用使用的是std::visit. 如果您“只想”选择该功能,您将获得 ,std::variant如果您愿意并且可以自己调用该功能。


    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;
}
Run Code Online (Sandbox Code Playgroud)