Search code examples
c++templatesc++14variadic-templatesdecltype

C++ / variadic template & parameter pack using decltype(lambda)


I am sorry to ask a question that was may be asked before, but I searched long enough and did not find an answer.

My problem is that I would like to call a template function of type template <typename GenericLambda, typename... LambdaArgs> without the need to always write decltype(my_lambda) first in the template parameters.

    #include <functional>
    #include <string>

    template <typename GenericLambda, typename... LambdaArgs>
    auto lambda_to_mem_fn() {
        auto ptr = &GenericLambda::template operator() < LambdaArgs... > ;
        auto as_mem_fn = std::mem_fn(ptr);
        return as_mem_fn;
    }

    auto my_lambda = [](auto x, auto y) { return x + y; };


    // imaginary function
    template <????>
    auto make_lambda_to_mem_fn(GenericLambda generic_lambda) 
    {
        // Extract lambda args types and forward them to lambda_to_mem_fn
        using GenericLambda = decltype(generic_lambda);
        lambda_to_mem_fn<GenericLambda, LambdaArgs...>();
    }


    void test() {
        // How to remove the need to write decltype(my_lambda) ?
        auto as_mem_fn = lambda_to_mem_fn<decltype(my_lambda), int, int>;

        // I would like to write:
        auto as_mem_fn2 = make_lambda_to_mem_fn<int, int>(my_lambda);
    }

I need a solution that is portable (i.e works on gcc, clang and msvc).

I'm scratching my head since quite some time in this, and would appreciate some help ;-)

Link to compiler explorer snippet: https://godbolt.org/z/pFk09J


Solution

  • The restriction where a parameter pack (if present) must be the final parameter in a template parameter list applies only to primary class templates. If the type can be deduced or defaulted, it can appear after the parameter pack:

    template <typename... LambdaArgs, typename GenericLambda>
    auto make_lambda_to_mem_fn(GenericLambda generic_lambda) 
    {
        return lambda_to_mem_fn<GenericLambda, LambdaArgs...>();
    }
    

    Any template arguments will be consumed by LambdaArgs, while GenericLambda will be deduced from the argument expression.