Skip to main content
GameDev.net gamedev.net
🔒 Locked

c++ function pointers

Started by dpadam450 Jul 9, 2014 at 5:11 AM 23 replies 6.7k views
Original Post
dpadam450
dpadam450

8 Years never needed a function pointer and I can't find a good example.

#include
using namespace std;

// Basic Function
int AddOne(int a)
{
return a + 1;
}

// I want a function that returns a pointer to AddOne so I can call it

// This declaration does not work, what is the delcaration to return the function as a pointer.
int (*)(int) GiveMeFunctionPointer()
{
return &AddOne
}

void main()
{
int (*foo)(int) = &AddOne // Cool foo is a pointer to a function taking an int

int (*foo2)(int) = GiveMeFunctionPointer(); // This is what I want to use...

cout << foo(2);
system("pause");
}

NBA2K, Madden, Maneater, Killing Floor, Sims 
SiCrane
SiCrane
The easiest way is to use a typedef. Ex: typedef int (*function_type)(int). Then function_type GiveMeFunctionPointer()
Samith
Samith

I second SiCrane, If you want to know what it would look like without typedefs, though:


int AddOne(int a)
{
    return a + 1;
}

int (*GiveMeFunctionPointer())(int)
{
    return &AddOne
}

Function pointer types are weird. It sort of goes around the function declaration.

dpadam450
dpadam450

Going to apply that to my actual code now..........does anyone know what that actually unrolls into? I don't mind typdef's for this case, I just hate typdef everything to a typdef item with a a typdef vector etc. I usually avoid them for readability.

// Obviously this doesnt work. Just curious what the signature without the typdef would be
int (*function_type)(int) GiveMeFunctionPointer()

{

}

Thanks.

NBA2K, Madden, Maneater, Killing Floor, Sims 
dpadam450
dpadam450

Function pointer types are weird. It sort of goes around the function declaration.

I did try something like that I guess I didnt have it correct. Either way typdef has worked in my engine. Sweet.

NBA2K, Madden, Maneater, Killing Floor, Sims 
ProtectedMode
ProtectedMode

Why not use std::function? It's a lot more flexible and safer.

Bregma
Bregma




I usually avoid them for readability.

That's odd. They were explicitly developed for and I use them for enhanced readability.

Then again, I second the use of std::function.

Stephen M. Webb
Professional Free Software Developer
Eck
Eck




8 Years never needed a function pointer and I can't find a good example.

Function pointers are kind of a weird tool in your toolbox. People are normally taught function pointers in an academic/abstract setting and then they are quickly forgotten because you can get by without them on a day to day basis. So here is a real world example.

I recently used function pointers (C# delegates) in a generic Credit Card Processing library that I wrote for my employer. It needed to work across all the C# projects who had different data-layers. I had a very specific series of events I wanted to happen when sending a credit card transaction as it was being used to make it bullet proof.

  1. Save the credit card transaction attempt BEFORE sending to the processor - Status: About to Send
  2. Send the transaction to the processor
  3. Save the result of the credit card transaction - Status: Approved/Denied

I could have solved this problem with documentation. Hey jerkies! Do it like I told you! But, if they didn't use it correctly, the burden of figuring out the problem was going to be on my shoulders anyway. So I'd rather be sure.

I could have solved the problem with direct saves through one of the data layers. But then I'd have to copy/paste the code in each project and rewrite the saves for each data layer. If there was a bug, I'd have to fix it in each copy of the code... Bleh.

So, I decided to use function pointers (C# delegates). The signature was:


bool PersistTransaction(CreditCardTransactionInfo)

I didn't care how they saved it, I just tell them the info they need to save. If there is a problem saving the data, they should return false to me so I don't try to go through with the transaction. This allowed them to use the data layer they felt like using. Heck, they could have even saved it to a file instead of into the database if they felt like it.The more junior programmers started murmuring amongst themselves and claimed I was a dark sorcerer...

In games, you might use function pointers to control simple AI movements for sidescrolling shooters. Basic enemies might just move straight, others might follow a sin curve, and others track the player like a heat seeking missile. You can solve this problem without function pointers, but it opens up some neat possibilities.

- Eck

TheComet
TheComet

You think this is weird, get into pointer to class methods smile.png

Member function pointers aren't any more weird, they follow the same structure as function pointers after all:


typedef int (*function_type)(int); // function pointer
typedef int (SomeClass::*member_function_type)(int); // member function pointer

The only difference being you need an object or object pointer to call them on:


SomeClass object;
member_function_type member_func = &SomeClass::someMethod;
object.*member_func(25);
"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty
Azaral
Azaral

I must prefer functors. Don't have to deal with any extra weird syntax. Plus, they can store data.

SeanMiddleditch
SeanMiddleditch
Functors and function pointers both have their uses.

If you're writing a non-generic function that needs to refer to another function, use std::function:

void foo(std::function<int(float)> func) {
  int output = func(12.34f);
}
If you're writing a generic (templated) function, you can either continue to use std::function or use a template type:

template <typename Callable>
void foo(Callable&& func) {
  int output = func(12.34f);
}
The second form is a little worse in some ways because it lets you pass anything in to the function and you get the usual terrible template errors, but it's mildly more efficient in some cases on some compilers with some optimization flags on some versions. Just use std::function unless you have hard evidence (e.g. analyzed profiling data) that you need something else.
Sean Middleditch – Game Systems Engineer – Join my team!
SmkViper
SmkViper

Functors and function pointers both have their uses.

If you're writing a non-generic function that needs to refer to another function, use std::function:







void foo(std::function<int(float)> func) {
  int output = func(12.34f);
}
If you're writing a generic (templated) function, you can either continue to use std::function or use a template type:


template <typename Callable>
void foo(Callable&& func) {
  int output = func(12.34f);
}
The second form is a little worse in some ways because it lets you pass anything in to the function and you get the usual terrible template errors, but it's mildly more efficient in some cases on some compilers with some optimization flags on some versions. Just use std::function unless you have hard evidence (e.g. analyzed profiling data) that you need something else.



Might I ask why you are using a templated r-value reference (aka "universal reference") in your template example and not a const ref? Foo is not "sinking" the parameter and simply invokes the () operator on it.

Of course, if you were going to take func and stick it by value into a class member or something similar using std::forward then I could see why you'd do that.

Also, my personal experience (backed up with profiling data on the compilers I use) is that the templated version always produces better, or at least equivalent, code to std::function, and you don't have to worry about hidden allocations and copies of large function objects (i.e. lambdas with several capture variables). For example, std::function on one library has 3 pointers worth of data storage for small-block-optimization, while another library has 4 pointers worth of data storage. If your lambda is larger then that, the library has to allocate space for std::function, where it doesn't have to for the template.

So I end up using the templated version wherever possible, and std::function when I have to - usually because I'm storing the function in a class variable, or the function pointer is passed to a virtual function that may be overridden.
Chris_F
Chris_F




Might I ask why you are using a templated r-value reference (aka "universal reference") in your template example and not a const ref? Foo is not "sinking" the parameter and simply invokes the () operator on it.

In this case it might not be necessary to use a universal reference, but if foo called another function and wanted to pass along func, then it could do so with perfect forwarding.

SeanMiddleditch
SeanMiddleditch

Might I ask why you are using a templated r-value reference (aka "universal reference") in your template example and not a const ref? Foo is not "sinking" the parameter and simply invokes the () operator on it.


A const reference would bar the functor from having mutable state, imposing an unnecessary rule upon it. Universal references are a good default choice if you don't have a strong reason to prefer an lvalue reference, value, or const reference.
Sean Middleditch – Game Systems Engineer – Join my team!
georger.araujo
georger.araujo

8 Years never needed a function pointer and I can't find a good example.

I find The Function Pointer Tutorials to be a good resource. Pros: an easy read, has examples, talks about functors. Cons: old, doesn't cover std::function.

cdoubleplusgood
cdoubleplusgood

I second SiCrane, If you want to know what it would look like without typedefs, though:


int AddOne(int a)
{
    return a + 1;
}

int (*GiveMeFunctionPointer())(int)
{
    return &AddOne
}
Function pointer types are weird. It sort of goes around the function declaration.

In the "new" standard (C++11), you can use a type alias instead of typedef:


using PF = int(*)(int);

Or, without typedef or alias, C++11 allows trailing return types; the syntax may be somewhat clearer:


auto GiveMeFunctionPointer() -> int (*)(int)
{
    return &AddOne
}
cdoubleplusgood
cdoubleplusgood

I find The Function Pointer Tutorials to be a good resource. Pros: an easy read, has examples, talks about functors. Cons: old, doesn't cover std::function.

Also missing: lambdas, mem_fn, bind. In modern C++, especially lambdas are a "must know", IMO.
Chris_F
Chris_F




Or, without typedef or alias, C++11 allows trailing return types; the syntax may be somewhat clearer:

C++14 makes this even cleaner:



auto GiveMeFunctionPointer()
{
    return &AddOne
}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.