Search code examples
c++c++11lambdastdstd-function

C++ decompose and then recompose std::function


I would like to create a wrapper class of a std::function (WrapperFunction) that doesn't need templates to be built. So, I'm wandering if it is possible to create a std::function and decompose it in its return type, arguments and function (lambda) and passing them to the constructor of WrapperFunction. The main task of WrapperFunction class would be to store these three data and return them in a proper way (for example through three getters). The will is to instantiate and pass around this class to not propagate templates needed to make a std::function.

A not working pseudo-code example to show the idea could be:

auto f = std::function<bool(int, int)>([](int a, int b){ return a == b;});

ReturnType rt = f.give_me_return_type;
Arguments args =  f.give_me_args;
Lambda lambda = f.five_me_lambda;

auto functionWrapper = FunctionWrapper(rt, args, lambda);

auto result = std::function<functionWrapper.getReturnType()(functionWrapper.getArguments())>(functionWrapper.getLambda());

Is possible to do that? or does exist something similar?


Solution

  • Is possible to do that? or does exist something similar?

    Short answer: no.

    Long answer.

    You ask to decompose a std::function initialized with a lambda in three components

    • 1) the return type
    • 2) the list of type arguments
    • 3) the original lambda

    The point (1) is simple to obtain. Not in the form of a rt variable

    ReturnType rt = f.give_me_return_type;
    

    but in the form of a using type alias

    using ReturnType = typename decltype(f)::result_type;
    

    The point (2) is more because there isn't possible make a using alias for a variadic list of types; the best I can imagine is to wrap the variadic list in a template-template container; std::tuple is the first that come in my mind.

    The best I can imagine is the develop of a type traits

    template <typename>
    struct funcArgTupler;
    
    template <typename R, typename ... Args>
    struct funcArgTupler<std::function<R(Args...)>>
     { using type = std::tuple<Args...>; };
    

    and use it as follows

    using ArgTuple   = typename funcArgTupler<decltype(f)>::type;
    

    The point (3), in general, is impossible because std::function can be initialized not only with lambda but also simple function pointers, struct/class methods and static struct/class methods.

    The type std::function give you a template method, target(), that return a pointer to the stored callable; the problem is that you have to know the type of the stored callable. And the type of a lambda is unique, so you have to register it somehow.

    The best I can imagine is register the original lambda in a variable

    auto l1 = [](int a, int b){ std::cout << "l1" << std::endl;
                                return a == b;};
    
    auto f = std::function<bool(int, int)>(l1);
    

    and get it

    auto l2 = f.target<decltype(l1)>();
    
    if ( l2 )
       (*l2)(1, 2); // print l1
    

    Said this, I don't know if make sense create a FunctionWrapper as you ask.