87

Whats the difference between std::function<> and a standard function pointer?

that is:

typedef std::function<int(int)> FUNCTION;
typedef int (*fn)(int);

Are they effectively the same thing?

0

4 Answers 4

69

A function pointer is the address of an actual function defined in C++. An std::function is a wrapper that can hold any type of callable object (objects that can be used like functions).

struct FooFunctor
{
    void operator()(int i) {
        std::cout << i;
    }
};

// Since `FooFunctor` defines `operator()`, it can be used as a function
FooFunctor func;
std::function<void (int)> f(func);

Here, std::function allows you to abstract away exactly what kind of callable object it is you are dealing with — you don't know it's FooFunctor, you just know that it returns void and has one int parameter.

A real-world example where this abstraction is useful is when you are using C++ together with another scripting language. You might want to design an interface that can deal with both functions defined in C++, as well as functions defined in the scripting language, in a generic way.

Edit: Binding

Alongside std::function, you will also find std::bind. These two are very powerful tools when used together.

void func(int a, int b) {
    // Do something important
}

// Consider the case when you want one of the parameters of `func` to be fixed
// You can used `std::bind` to set a fixed value for a parameter; `bind` will
// return a function-like object that you can place inside of `std::function`.

std::function<void (int)> f = std::bind(func, _1, 5); 

In that example, the function object returned by bind takes the first parameter, _1, and passes it to func as the a parameter, and sets b to be the constant 5.

Sign up to request clarification or add additional context in comments.

7 Comments

@makar It's the identifier used by std::bind to refer to the first argument of the resulting function. It's a bit like: void bound(int _1) { func(_1, 5); }.
The link here mentioned another different between function pointer and std::function: The lambda capture is unable to be used in function pointer.So if you try to use lambda [&](int a, int b){/*blah*/}, or [=](int a, int b){/*blah*/}, you will have a compile error. The only valid format is [](int a, int b){/*blah*/}
Using bind is no longer recommended. We have lambda's, which are a nicer mechanism. While bind is not deprecated - I wouldn't it make it look like I were promoting its use.
std::function may be more convenient but it will cost you some performance over the raw function pointer ,when used with std::bind.
The last example with std::bind looks a lot like partial application in functional programming. Didn't know such a thing was possible in C++.
|
69

They are not the same at all. std::function is a complex, heavy, stateful, near-magic type that can hold any sort of callable entity, while a function pointer is really just a simple pointer. If you can get away with it, you should prefer either naked function pointers or auto-bind/auto-lambda types. Only use std::function if you really need a systematic way of organizing a heterogeneous collection of callable entities, such as functions, functors, capturing lambdas and bind expressions.


Update: A bit of explanation about auto types: Compare the following two functions:

void do_something_1(std::function<void(int)> f, int a) { f(a); }

template <typename F, typename A> void do_something_2(F f, A a) { f(a); }

Now imagine invoking them with a lambda or a bind expression:

do_something_X([foo, &bar](int n){ bar += n*foo; },     12);
do_something_X(std::bind(X::bob, &jim, true, _1, Blue), 13);

The second version with the template is more efficient, because in both cases, the argument F is deduced to the actual, unknowable type of the expression. The first version, with std::function, isn't a template and may look simpler and more deliberate, but it always forces the construction of the std::function object, and quite possibly carries multiple type erasure and virtual dispatch costs.

7 Comments

This is kinda confusing, mind explaining this further? that is, exactly when to use std::function, and when to use a function pointer. Also, what is a "auto-bind/auto-lambda types"
@aCuria: If you want to make a container of callable things and you want to put all sorts of mixed types in there, then you have to use std::function and convert everything. But if you know that you always have genuine free functions, you can just make a container of function pointers. I'll expand on the auto-preference in the actual post in a bit.
Do the calls to do_something in the update need a second parameter (corresponding to the a in do_something_1 and do_something_2, or am I completely confused about how they're working?
Function pointers won't work with lambdas capturing context variables. If you expect to use lambdas, std::function is a better choice.
@JanVčelák While this is true, the template can handle also lambdas capturing context. So when passing such lambdas you are not limited to use std::function but can also use templates.
|
20

A std::function has state. It can hold additional parameters "bound" into it.

These parameters can range from things like other classes, other functions, or even this pointers for member function calls.

The replacement function pointer is not typedef int (*fn)(int);

It is typedef int (*fn)(void*,int);, with the void* reperensting the state that would be hidden in the std::function.

Comments

9

No.

One is a function pointer; the other is an object that serves as a wrapper around a function pointer.

They pretty much represent the same thing, but std::function is far more powerful, allowing you to do make bindings and whatnot.

6 Comments

Is there a simple way of converting between these two?
@phimuemue You write a wrapper function that takes a std::function as the data pointer, and then calls the std::function. The function pointer must have a data pointer in order for this to work.
... which is not a conversion.
-1 Not because it's incorrect, but imprecise and unclear. First, you should explain that std::function is a wrapper a round a callable object (such as a function pointer, but not limited to just that). Also, std:: function is just a wrapper, you don't use it specifically to make bindings.
-1: Agreed with Paul. This answer needs more detail.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.