7

After going though a question on std::bind, I was wondering if it was possible to hold a vector of functions created by std::bind so I can avoid using std::function and its heavyweight wrapping.

#include <iostream>
#include <functional>
#include <typeinfo>
#include <vector>

int add(int a, int b) {return a + b;}

int main() {

    //I believe this here is just a special type of bound function.
    auto add2 = std::bind(add, std::placeholders::_1, 2);
    auto add3 = std::bind(add, std::placeholders::_1, 3);

    //Yup.
    std::cout << typeid(add2).name() << std::endl;
    //Here's the type of the second function
    std::cout << typeid(add3).name() << std::endl;

    //Is there a nicer way to do this?
    std::vector<decltype(std::bind(add, std::placeholders::_1, 1))> vec;

    return 0;   
}

Although it's possible of to create a vector of std::bind functions, is there a way I don't have to provide a specific case of a bound function in order to declare a container without an empty/dummy type of a function made from std::bind?

Community
  • 1
  • 1
CinchBlue
  • 6,046
  • 1
  • 27
  • 58
  • Why not `std::vector vec;`? Or do you hypothetically want to `emplace` every vector element? – SU3 Jun 18 '15 at 03:35
  • I want to be able to initialize without having to provide any bound function. So no inline `std::bind` or bound function before hand. – CinchBlue Jun 18 '15 at 03:42
  • 2
    Well, `bind` returns an unspecified type, so you'll need a `bind` expression to be able to deduce the type. Anyway, the utility of your `vector` is rather limited because changing just about anything other than the bound argument in that `bind` expression is going to change the resulting type, so you don't have a lot of choice of `bind` expressions you can add to that `vector`. – Praetorian Jun 18 '15 at 04:15
  • @Praetorian: is even that guaranteed? I'd expect an implementation's free to encode the integer literal (above `2`, `3`) in the type (e.g. perhaps as template parameters, though it need not even be through a user-exposed Standard C++ feature given we're talking about the implementation).... 'twould be weird, but "returns an unspecified type" leaves a lot of leeway. – Tony Delroy Jun 18 '15 at 05:32
  • @TonyD Is what part guaranteed? The type not changing along with the bound argument? I don't think it is. TC's comment on the answer below seems to be saying the same thing. But I'd imagine that it holds true for most `bind` implementations. – Praetorian Jun 18 '15 at 05:54
  • @Praetorian yes that... just pointing out that even your "because changing just about anything *other than the bound argument*" was a bit optimistic, as even changing that could be a problem. – Tony Delroy Jun 18 '15 at 06:23
  • 4
    @VermillionAzure This question could be improved by quantifying the "weight" refered to in "*so I can avoid using std::function and its heavyweight wrapping"*, relative to the weight when using `bind`, so you're showing that at least in your implementation - with certain compiler options etc - there's actual incentive to avoid `function` and not just FUD. (FWIW, with GCC on coliru I'm seeing `sizeof` 32 bytes for `function` vs. 16 for `bind`, but there may be indirect memory use beyond that). – Tony Delroy Jun 18 '15 at 06:27
  • be aware: in order to optimize usually one has write *more* code than using convenience functions. so I one way to control the weight of `std::function` is to write a "closure wrapper" yourself that fits your needs and is cheaper than `std::function`. This requires you to know where the expense of `std::function` comes from. – Alexander Oh Jun 18 '15 at 07:36

2 Answers2

2

So, it appears that this isn't possible--std::bind doesn't appear to have a normally nameable/explicit type--the type is usually generated according to the signature of the bound function, and doesn't appear to be specifiable. Using std::function seems to be the only way to wrap std::bind functions and store them in a vector.

Even for lambdas, this doesn't seem possible--using a wrapper in the form of std::function seems to be the go-to answer, despite the increased size of the resulting function-object.

Possible alternatives might be storing Functor objects designed to mimic closures couples with generic objects with a type-checking layer (though this seems quite heavy). Whatever the case, using std::function seems to be the cleanest solution.

Community
  • 1
  • 1
CinchBlue
  • 6,046
  • 1
  • 27
  • 58
0

How about this?

#include <iostream>
#include <functional>
#include <vector>

int add(int a, int b) { return a + b; }

using bound_add_t = decltype(std::bind(add, std::placeholders::_1, int()));

int main() {
  std::vector<bound_add_t> vec;
  vec.emplace_back(add,std::placeholders::_1, 1);
  vec.emplace_back(add,std::placeholders::_1, 2);
  vec.emplace_back(add,std::placeholders::_1, 3);

  for (auto &b : vec)
    std::cout << b(5) << std::endl;

  return 0;   
}
SU3
  • 5,064
  • 3
  • 35
  • 66
  • No, sorry, I want a real solution, not just a simple `using` alias. – CinchBlue Jun 18 '15 at 05:26
  • 1
    I just really think what you are asking is not possible, if you want to maintain portability. `std::bind` constructor returns an `/*unspecified*/`, so it's implementation dependent. I suppose, if you are only concerned with a single compiler, there probably is an internal template that can give you the type, but I doubt that calling that will make your syntax shorter then using `decltype`. And you must provide a type as a template argument to the vector. You can just stick `auto` there or something of that sort. – SU3 Jun 18 '15 at 06:14
  • You also can just dynamically allocate `bind` objects and have a `vector` of `void*`, because you'll have to cast back to the proper type to call the `operator()`. – SU3 Jun 18 '15 at 06:20