Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

modern c++ alternative to function pointers

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.

like image 473
hg_git Avatar asked Jun 10 '15 06:06

hg_git


3 Answers

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) ;
like image 68
marom Avatar answered Sep 18 '22 04:09

marom


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.

like image 26
PaperBirdMaster Avatar answered Sep 21 '22 04:09

PaperBirdMaster


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 T> 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.

like image 44
Puppy Avatar answered Sep 20 '22 04:09

Puppy