What is "void (*)()", and what is good or bad about it?

I just found this out from randomly porting some C code to C++, it seems to be some kind of polymorphism but only with functions, it's kinda crazy to me. I though that you can only mess with functions only with <functional>, and it also doesn't only work with void...

Here's an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <vector>

std::vector<void (*)()> waaat;

void cat(){
    std::cout<<"meow\n";
}

void boo(){
    std::cout<<"boooooo\n";
}

void dog(){
    std::cout<<"woof\n";
}

int main()
{
  waaat.emplace_back(cat);
  waaat.emplace_back(dog);
  waaat.emplace_back(cat);
  waaat.emplace_back(boo);
  
  for(auto wat: waaat)
    wat();

  return 0;
}


What I mainly want to know is what is it called (because I can't find it), and if there is a good reason why this trick isn't widely used over polymorphism (like hell, you don't even need to allocate it with "new", and delete it, or de-reference it...).
Last edited on
it seems to be some kind of polymorphism with voids, it's kinda crazy to me,


It's not polymorphism. It's just a function pointer.

1
2
int *p;   // p is a pointer to an integer
void (*foo)();  // foo is a pointer to a function that returns void, and takes no parameters 


I though that you can only mess with functions only with <functional>


Function pointers vastly pre-date <functional>. In fact <functional> just takes function pointers and makes them easier to use.

What I mainly want to know is what is it called (because I can't find it)


"Function pointer" =P

and if there is a good reason why this trick isn't widely used over polymorphism


Raw pointers are easier to screw up. With polymorphism you have compile-time checks in place so you know you are calling a valid function.

With a raw function pointer, you could be calling anything -- and if it hasn't been initialized properly, then you are completely hosed. There can be no compile-time checks to ensure the pointer you are using is valid.

(like hell, you don't even need to allocate it with "new", and delete it, or de-reference it...)


You shouldn't be manually delete'ing anyway. Use smart pointers.

RAII + smart pointers + polymorphism = you can practically never go wrong.

raw pointers + manual memory management = it's very easy to go wrong.
I'll just add some things to Disch's comment

Function pointers can not only be declared like void (*func)();
it's more like, the left parameter (void) tells you the return parameter of func.
the second brackets are used to give parameters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int add(int val1, int val2)
{
    return val1 + val2;
}
int mult(int val1, int val2)
{
    return val1 * val2;
}

int main(void)
{
    int (*func)(int, int) = add;
  
    for(int i = 0; i < 50; ++i)
    {
        std::cout << "result: " << func(i, i) << std::endl;

// dynamically switching where it points to
        if(func == add) func = mult;
        else func = add;
    }
}


So, when declaring, you tell the return type and the parameter types.
since you are familiar with std::function, it has something like this hidden somewhere inside, and uses templates too.
std::function<int(int, int)> func;
the return parameter is int, and the passed parameter list contains of int and int (bad example but I'll stick to it :b)
It basically equals this:
int (*func)(int, int);
but just... better ^^
Last edited on
Side note: People uses & and * with function pointers... but... they don't really change anything. http://ideone.com/PHaYxC
A function reference cannot be null.
Side note: People uses & and * with function pointers... but... they don't really change anything.

Thank you man!
I could swear I had some compiler issues a few months back in time and they mysteriously disappeared.
After they disappeared I had a & before the function names, so I thought that that had to be the reason x'D
Gamer2015 wrote:
After they disappeared I had a & before the function names, so I thought that that had to be the reason x'D
Not quite.
1
2
3
4
5
6
void f();

void (*fp1)() = &f; //valid
void (*fp2)() = f; //valid
void (&fr1)() = &f; //not valid
void (&fr2)() = f; //valid 
http://ideone.com/AhhcGE
Since we posted at the same time, you may have missed my previous post.
Last edited on
I think ill be using these in small programs in the future that need a state system, function pointers are very small and simple :)
A function reference cannot be null.
That's not only true for function references, right?
I though a reference can never be null

Since we posted at the same time, you may have missed my previous post.
Yup, thanks for the more detailed explanaition :)

I think ill be using these in small programs in the future that need a state system, function pointers are very small and simple :)
that's a good use for them :)
But you should still prefer std::function
I wrote a SDL2 Button class with a function pointer (but I am glad that I finally changed it to std::function)
Last edited on
I still prefer std::function over straight function pointers. The syntax is waaaaay easier to remember and you can bind not-quite-matching functions to it.

The syntax for pointer to member functions still confuses me and I still have to double-check it every time I need it.
@Gamer2015: A function reference is a reference, so yes. I would say a function pointer is a pointer, but it's sort of weird because it gets special treatment.

Also, I 100% agree with Disch about using std::function.
Last edited on
++ for <functional> and std::function.
Pointer-to-member syntax doesn't confuse me that much anymore... but std::bind helps *a lot*.
(@LB: Oops, forgot to mention that.)
Last edited on
Topic archived. No new replies allowed.