modern c++ alternative to function pointers

15.3k views Asked by At

I've been using function pointers till now, like this format in c++. I do have some uses now and then and I'm wondering is there anything else introduced in c++11/14 as their alternative.

#include <iostream>
using namespace std;

void sayHello();
void someFunction(void f());

int main() {

    someFunction(sayHello);
    return 0;
}
void sayHello(){
    std::cout<<"\n Hello World";
}
void someFunction(void f()){
    f();
} 

I did take a look at this question but couldn't understand any advantages over traditional use of function pointers. Also I would like to ask , is there anything wrong (not recommended) thing with using function pointers since I never see anyone using them. Or any other alternative present.

4

There are 4 answers

1
Puppy On BEST ANSWER

Also I would like to ask , is there anything wrong (not recommended) thing with using function pointers since I never see anyone using them.

Yes. Function pointers are terrible, awful things. Firstly, they do not support being generic- so you cannot take a function pointer that, say, takes std::vector<T> for any T. Secondly, they do not support having bound state, so if at any time in the future, anybody, ever, wishes to refer to other state, they are completely screwed. This is especially bad since this includes this for member functions.

There are two approaches to taking functions in C++11. The first is to use a template. The second is to use std::function.

The template kinda looks like this:

template<typename F> void func(F f) {
    f();
}

The main advantages here are that it accepts any kind of function object, including function pointer, lambda, functor, bind-result, whatever, and F can have any number of function call overloads with any signature, including templates, and it may have any size with any bound state. So it's super-duper flexible. It's also maximally efficient as the compiler can inline the operator and pass the state directly in the object.

int main() {
    int x = 5;
    func([=] { std::cout << x; });
}

The main downside here is the usual downsides of templates- it doesn't work for virtual functions and has to be defined in the header.

The other approach is std::function. std::function has many of the same advantages- it can be any size, bind to any state, and be anything callable, but trades a couple off. Mainly, the signature is fixed at type definition time, so you can't have a std::function<void(std::vector<T>)> for some yet-to-be-known T, and there may also be some dynamic indirection/allocation involved (if you can't SBO). The advantage of this is that since std::function is a real concrete type, you can pass it around as with any other object, so it can be used as a virtual function parameter and such things.

Basically, function pointers are just incredibly limited and can't really do anything interesting, and make the API incredibly unflexible. Their abominable syntax is a piss in the ocean and reducing it with a template alias is hilarious but pointless.

0
Werner Erasmus On

I did take a look at this question but couldn't understand any advantages over traditional use of function pointers. Also I would like to ask , is there anything wrong (not recommended) thing with using function pointers since I never see anyone using them.

  • Normal "global" functions typically don't/can't have state. While it's not necessarily good to have state during traversal in functional programming paradigm, sometimes state might come in handy when it relates orthogonally to what has been changed (heuristics as example). Here functors (or function objects) have the advantage.

  • Normal functions don't compose very well (creating higher level functions of lower level functions.

  • Normal functions don't allow for binding additional parameters on the fly.

  • Sometimes normal functions can act as replacement for lambdas, and visa versa, depending on the context. Often one wouldn't want to write a special function just because you have some very local/specific requirement during "container traversal".

1
PaperBirdMaster On

As an alternative to traditional function pointers, C++11 introduced template alias which combined with variadic templates could simplify the function pointer sintax. below, an example of how to create a "template" function pointer:

template <typename R, typename ...ARGS> using function = R(*)(ARGS...);

It can be used this way:

void foo()                { ... }
int bar(int)              { ... }
double baz(double, float) { ... }

int main()
{
    function<void>                  f1 = foo;
    function<int, int>              f2 = bar;
    function<double, double, float> f3 = baz;

    f1(); f2({}); f3({}, {});
    return 0;
}

Also, it can deal neatly with function overloads:

void overloaded(int)      { std::cout << "int version\n"; }
void overloaded(double)   { std::cout << "double version\n"; }

int main()
{
    function<void, int>    f4 = overloaded;
    function<void, double> f5 = overloaded;

    f4({}); // int version
    f5({}); // double version
    return 0;
}

And can be used as a pretty neat way to declare function-pointers parameters:

void callCallback(function<int, int> callback, int value)
{
    std::cout << "Calling\n";
    std::cout << "v: " << callback(value) << '\n';
    std::cout << "Called\n";
}

int main()
{
    function<int, int> f2 = bar;
    callCallback(f2, {});
    return 0;
}

This template alias could be used as an alternative of std::function which doesn't have its drawbacks nor its advantages (good explanation here).

Live demo

As a brief, I think that template alias combined with variadic templates is a good, nice, neat and modern C++ alternative to raw function pointers (this alias still are function pointers after all) but std::function is good, nice, neat and modern C++ as well with good advantages to take into account. To stick in function pointers (or alias) or to choose std::function is up to your implementation needs.

5
marom On

The question you mention suggest std::function but does not emphasize (or mentions at all) its value when combined with std::bind.

Your example is the simplest possible, but suppose you have a

std::function<void (int, int)> f ;

A function pointer can do more or less the same things. But suppose that you need a function g(int) which is f with second parameter bound to 0. With function pointers you can't do much, with std::function you can do this:

std::function<void(int)> g = std::bind(f, _1, 0) ;