0x6B6F77616C74
0x6B6F77616C74

Reputation: 2630

Pointer to a procedure

Does it possible to invoke a procedure via pointer? I haven't found anything about it on the internet, but the following experimental code compiles without warnings.

#include <iostream>
#include <ctime>

using namespace std;

void PrintCurrentClock()
{
    cout<<clock()<<endl;
}

void PrintCurrentTimeStamp()
{
    cout<<time(0)<<endl;
}


int main()
{
    void* pF = PrintCurrentClock;

    pF;

    pF = PrintCurrentTimeStamp;

    pF;

    system("Pause");
    return 0;
}

The output is empty, as if the *pF was somewhat "transparent".

Upvotes: 3

Views: 1518

Answers (4)

Loki Astari
Loki Astari

Reputation: 264571

Yes you can:

Though the type-system is a bit convoluted.
So it is usual to wrap a pointer to a function in a typedef.

typedef <returnType> (*<TypeName>)(<ParameterList>);

// In your case:

tpyedef void (*PtrToTimeFunc)();

// Now your pointer types look like normal variables:
PtrToTimeFunc  pf = &PrintCurrentTimeStamp;

// Calling them is like normal:
pf(); // If it needed parameters then put them as normal.

Because the C++ compiler can not past function pointers to optimize the code; in C++ it is common to use functors. A functor is an object that behaves like a function, but because it is an object can also contain state (like a closure in other languages).

struct MyFunctor
{
    // To make a functor just override the operator ()
    // You can make it return any type and take any parameters (just like a function).
    int operator()() const
    {
        return time(NULL);
    }

    // Add any state and constructors etc. you like here.
    // Though note: because I declared the operator() as const you
    // can not mutate the state via the function call (remove cost)
    // if you want to do that.
};

// declaring a functor just like any-other object.
MyFunctor  myFunctor;

// calling. Just like a function.
myFunctor();

OK. So why is this more useful than a pointer.

When used with the standard algorithms. You define the algorithm with the type of the functor thus the compiler generates the algorithm code it also has available all the code for the functor (unlike the function pointer which it can not optimize past). This allows the compiler to do a full set of optimizations in place.

std::generate(cont.begin(), cont.end(), myFunctor);

So in C++ 11 we have introduced lambdas. These are basically functions that can be defined in place. But it is easier to think of lambdas as compiler generated functors (as they can capture the current state as part of their definition).

std::generate(cont.begin(), cont.end(), [](){return time(NULL);});

// [] - defines the state that is being captured.
//      Think of this like the constructor capturing objects.
//      In this case take no state.
//
// () - parameter list
//      In this case no parameters
//
// {} - The code.

A more interesting example:

std::vector<int> data; // fill vector
std::for_each(data.begin(), data.end(), [](int& value){value += 4;}); // Add 4 to each member.

Upvotes: 1

Matteo Italia
Matteo Italia

Reputation: 126867

What you want are function pointers:

void (*pF)() = PrintCurrentClock;
pF();

(some people argue that writing &PrintCurrentClock is better style)

Notice that, as you can see, function pointers have a quite awkward syntax (especially if you start to have function pointers with "strange" arguments) and can prevent some compiler optimizations to work correctly, so they are usually used only when actually needed (e.g. for callbacks, although in C++ functors are often preferred).


Why does your code compile, although it doesn't work as expected? In

void* pF = PrintCurrentClock;

PrintCurrentClock is a void (*pF)(), which is implicitly converted to void *1; then, writing

pF;

you are evaluating the expression pF and discarding its return value - which is effectively a no-op (exactly as if you wrote 5; or any other expression that does not involve a function call).


  1. Actually, this conversion shouldn't happen automatically, since the C++ standard do not provide an implicit conversion from function pointers to void *. Compiling this with g++ 4.6 correctly produces the errors:

    matteo@teolapmint ~/cpp $ g++ -Wall -Wextra -ansi -pedantic testfuncptr.cpp 
    testfuncptr.cpp: In function ‘int main()’:
    testfuncptr.cpp:19:20: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive]
    testfuncptr.cpp:21:15: warning: statement has no effect [-Wunused-value]
    testfuncptr.cpp:23:22: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive]
    testfuncptr.cpp:25:23: warning: statement has no effect [-Wunused-value]
    testfuncptr.cpp:27:39: error: ‘system’ was not declared in this scope
    

    which tells you that those conversions are not admitted, that the pF; instructions are no-ops and that you forgot #include <cstdlib> (although system("pause"); is not portable anyway).

Upvotes: 4

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726809

Both C and C++ have function pointers that let you do what you are looking for:

void (*pf)(void);
pf = FunctionWithVeryVeryVeryLongNameThatPrintsTheCurrentClockStateUsingStdCoutOutputStream;
pf();

The void in parentheses is optional.

The reason you did not find anything on the topic is that for historic reasons both functions and procedures in C are called functions (the reason is that there were no void in the original language - procedures returned int by default, and the return value was ignored). C++ inherited this naming convention.

Upvotes: 5

Michael
Michael

Reputation: 58467

Your way of creating and using the function pointer is slightly off. Here's an example of how to do it:

void proc() {
    cout << "Hello from proc" << endl;
}

...

void (*pproc)() = proc;

pproc();

Upvotes: 2

Related Questions