-2

I was reasoning about how to write and design several functions that are supposed to deal with a specific file format which can possibly have different implementations and different versions, and each one needs a different way of decoding such information from the file .

I was browsing through the standard library as I usually do and I get a remainder that std::function exist, but the thing is I can't figure out why I can possibly be interested in using std::function, one of the first rules when programming in C and C++ is that if you don't have to refer to things you don't necessarily have to name them, and you can get unnamed data structures and unnamed/lambda functions, but functions usually have a name, and the type for a lambda is still implementation defined as far as I can remember, so what is the need for std::function ?

For example in my case I was thinking about using a map or an hash table ( but the number of functions involved is really small anyway, 2-3 max for now ) with a pair composed of tag ( which represents the version/implementation of the file format ) + functions, and I was wondering why I can't just use std::string and functions pointers as the 2 types for each pair; and I also can't really understand why we have std::function in the standard library .

I mean, when it's the case when you need a function that is unnamed and you need an object to describe its state ?

user2485710
  • 9,451
  • 13
  • 58
  • 102
  • 1
    Isn't that explained well enough in the [available reference material](http://en.cppreference.com/w/cpp/utility/functional/function)? – πάντα ῥεῖ Nov 23 '14 at 01:31
  • @πάνταῥεῖ not with design and usecases for that class as given by some member of some committee , no. – user2485710 Nov 23 '14 at 01:32
  • _"with design and use cases for that class ..."_ Make this subject clear in your question then. – πάντα ῥεῖ Nov 23 '14 at 01:34
  • 6
    Here's [N1402](http://open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1402.html) that may contain valuable information. Here's a tangentially related question that talks about use cases for [`std::function`](https://stackoverflow.com/questions/14677997/stdfunction-vs-template). –  Nov 23 '14 at 01:35
  • 4
    Use `std::function` if and only if you need a *heterogeneous* collection of callable objects. Don't use it if you only need a single, callable thing (prefer a template in that case). – Kerrek SB Nov 23 '14 at 02:07

3 Answers3

6

The question has been answered multiple times, with answerers from different perspectives.

(sorted by ascending question number.)

My guess is that std::function is there to make lambda easy to use.

Basically, functors are more convenient when you need to accomplish small things. Interfaces (abstract base class, or ABC, in C++) are more suitable when things grow beyond the "small" scale.

More specifically:

  • When you need to implement a "one-liner" callback function, accept a std::function and implement with a lambda.
  • Such "one-liner" arises from:
    • "One-liner". Enough said.
    • Glue code, where you need to adapt the call signatures just a little bit to make the call pass through. Use std::bind along with std::function and lambda.
  • It saves you from:
    1. Creating an interface (abstract base class, ABC) with those boilerplate,
    2. Provide an empty body for a trivial virtual destructor (as required by some C++ compilers),
    3. Create a class that inherits from that ABC,
    4. Create a constructor for the "captured data" (closure) and store them in private fields,
    5. Finally you can write the code.
  • With lambda, #1 goes into the std::function signature, skip #2 and #3, put #4 in a comma-separated list inside square brackets, and put #5 inside curly braces. Use auto liberally.

Anything that goes beyond "one-liner", or "one callback function", deserves an interface (ABC).

Also, if your code base is not compiled as a single piece (i.e. separations of libraries and linking), then any callback functions exposed on the library will preferably need to use an interface (ABC). This may or may not be an issue depending on your compiler and linking method.

Community
  • 1
  • 1
rwong
  • 6,062
  • 1
  • 23
  • 51
  • C++ functors have almost nothing to do with this, they are just class types with a custom `()` operator, the other answers are a nice read tho . – user2485710 Nov 23 '14 at 01:56
  • 1
    @user2485710 The design choice between functors and interfaces is the same design choice you are wondering about. In C++, there are multiple (and previously incompatible) ways of doing the same thing, with function pointer and functor being two of those. `std::function` is the great unifying force of those things introduced by C++11. – rwong Nov 23 '14 at 02:01
  • `std::function` is much older than lambda functions in C++, it's not just to make them easy to use. – Jonathan Wakely Nov 23 '14 at 03:51
  • @JonathanWakely I stand corrected. I was unfamiliar with the history of Boost. – rwong Nov 23 '14 at 04:00
6

std::function was based on the older boost::function which has good documentation, the introduction says:

Generally, any place in which a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead to allow the user greater flexibility in the implementation of the target. Targets can be any 'compatible' function object (or function pointer), meaning that the arguments to the interface designated by Boost.Function can be converted to the arguments of the target function object.

The N1402 proposal to add std::tr1::function also has a section describing the motivation for the feature. It was added to the standard because thousands of people had found boost::function useful for many years.

If you still don't understand why it's useful you probably don't understand where function pointers or callbacks are useful, so look that up.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • `std::function` is polymorphic and it usually achieves polymorphism through type erasure; I can't see the parallel with C-style function pointers. I think you are shooting too high . – user2485710 Nov 23 '14 at 16:24
  • 5
    I think you're not thinking broadly enough. The comparison with function pointers I quoted above is from the authors of `std::function`, maybe they understand it better than you do? Using type erasure is an implementation detail, the point of it is to be a more general version of a function pointer, that can store any form of callable object. It has to use type erasure to abstract away the difference between `int(*)()` and `struct F { int operator() const; };` and `[] { return 1; }` but type erasure is not what it's _for_, it's just how it achieves its purpose. – Jonathan Wakely Nov 23 '14 at 18:17
  • 1
    The goal is [closure (computer programming)](http://en.wikipedia.org/wiki/Closure_%28computer_programming%29), as it can be found in many other languages and was missing in C++ for decades. Simply speaking it is callable code with state (as in statefulness, and its protection from premature destruction). A function pointer with the size of `sizeof(void*)` cannot achieve closure. A member function pointer could, but then it can only be bound to member functions of that specific class. Note that to truly use it for closure one must typically use `shared_ptr` as well. – rwong Nov 23 '14 at 19:44
  • 2
    @rwong, that's one use, but not the only one. There are plenty of uses of `std::function` that are stateless, and plenty that are stateful without using `shared_ptr` (e.g. you can use `std::bind` or lambdas to capture state). – Jonathan Wakely Nov 24 '14 at 01:38
4

std::function<R(Args...)> type erases copy, destroy and invoke with Args... and return R, and implements move.

Start with a basic callback -- R(*)(Args...) with the Args... provided by the caller. Now a good callback has a void* you pass in to the caller, and they pass back -- now you have R(*)(void*,Args...). Next, we need to detatch and recycle the void* callback data -- so we have a void*, a R(*)(void*,Args...) and a void(*)(void*) cleanup. Next, we want value semantics -- so the caller also passes how to clone the void* -- a void*(*)(void*) clone function (value semantics are awesome, really).

And now you have a C-style version of a std::function<R(Args...)>. The std::function auto-generates the above in a constructor, and typical implementations store an interface to an abstract class that implememts the above for the passed in callable type.

So type erasure lets you take any value that supports the above type erased concepts and store them within a uniform type -- std::function<R(Args...)>.

This allows you to accept anything that matches your needs, and interact with it uniformly. You can store it in a public class, you can pass it to a dynamically loaded library, or otherwise to a chunk of code not directly dependent on the original choice of function and state.

You could use the C-style version, but it gets awkward wrapping it up.

There are variations of std::function that do away with the copy concept, and some that do away with destroy (ie, do not own), as even without that abstracting invoke is worthwhile.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • so this shines when I have different functions with different signatures, if, as it is in my case, I have an N number of functions all with the same signature there is no real advantage in using this type ? – user2485710 Nov 23 '14 at 16:26
  • @user24 no, each template instance of std function instances are for a single signature. It stores anything compatiple with the signature. It lets you store function pointers, lambdas, or classes with `operator()`. It will do conversion of compatible types (so `std::function` will take `int(int)` callable things) but that is secondary to its primary purpose. – Yakk - Adam Nevraumont Nov 23 '14 at 17:09
  • @user2485710, it's like a function pointer, despite your apparent refusal to believe it. A function pointer `double(*)(double)` has a fixed signature, but can refer to any function with that signature. A `function` has the same fixed signature but can refer to any callable object with that signature (including, but not limited to, anything that the `double(*)(double)` can refer to) – Jonathan Wakely Nov 23 '14 at 18:21
  • @user24 I added some details that might make it clearer. – Yakk - Adam Nevraumont Nov 23 '14 at 22:50