2

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?

max66
  • 65,235
  • 10
  • 71
  • 111
Squerut
  • 65
  • 3
  • 10
  • 5
    Doubt this is possible. An `std::function` isn't necessarily a lambda, and the best you could do with storing types is `typeid`. Why don't you want to use templates? Templates are the backbone of most modern C++ techniques. – Stephen Newell Mar 27 '18 at 12:28
  • Any reason you can't just wrap the function in a lambda? – UKMonkey Mar 27 '18 at 12:29
  • see [my answer here](https://stackoverflow.com/a/45718187/2610810) – Caleth Mar 27 '18 at 12:30
  • You have `std::function::result_type` for the return_type. for arguments, only available from interface for 1/2. Else you have to create a traits. – Jarod42 Mar 27 '18 at 12:33
  • 2
    You appear to lack the vocabulary to describe what you want. Based off my experience with similar questions, I'm betting you are writing some kind of scripting system? And you want to store a bunch of callbacks in one spot? In any case, you are describing a an *impossible solution* to an *undescribed problem* you have, and asking how to make the *impossible solution* work. In order to solve your problem and adapt your solution, we need to be told what the *undescribed problem* is. This is known as the X/Y problem. – Yakk - Adam Nevraumont Mar 27 '18 at 12:34
  • @UKMonkey no reason. Actually I can use a lambda instead of a std::function. If I would use lambdas, how the problem/solution could change? – Squerut Mar 28 '18 at 12:28
  • @Caleth I took a look to your answer; interesting, this would be exactly what I need! But, despite I have a c++17 compiler, I am not able to make example working (problems with **** standard library) – Squerut Mar 28 '18 at 12:39
  • 1
    @Squerut I've gone back and fixed up that example, now that we know the final state of C++17. It was lacking a `std::function` wrapping constructor. [See it working on coliru](http://coliru.stacked-crooked.com/a/457b099fdf18c9e4) – Caleth Mar 28 '18 at 13:33

1 Answers1

2

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.

max66
  • 65,235
  • 10
  • 71
  • 111
  • Ok, very explicative. After reading your answer, I agree with you about the "no sense" in creating **FunctionWrapper** class. I could use directly lambdas instead – Squerut Mar 28 '18 at 13:06