5

Is it possible in C++? For example I have a pointer to a function that takes no parameters and its return type is void:

void (*f)();

and and a function object:

class A
{
public:
    void operator()() { cout << "functor\n"; }
};

Is it possible to assign to f the address of an A object? And when I call f() to call the A functor?

I tried this but it doesn't work:

#include <iostream>
using namespace std;

class A
{
public:
    void operator()() { cout << "functorA\n"; }
};

int main()
{
    A ob;
    ob();
    void (*f)();
    f = &ob;
    f();       // Call ob();
    return 0;
}

I get C:\Users\iuliuh\QtTests\functor_test\main.cpp:15: error: C2440: '=' : cannot convert from 'A *' to 'void (__cdecl *)(void)' There is no context in which this conversion is possible

Is there any way to achieve this?

Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140

4 Answers4

5

You can't do it in the way you've specified, because:

  1. operator() must be a nonstatic function (standards requirement)
  2. a pointer to a non-static function must have an implicit parameter - the pointer to the class instance
  3. your call to f() does not give any indication on which instance of the object A your function is called

Using C++11 and std::function, as Stephane Rolland pointed out, may do the trick - you'll be specifying the pointer to the object in the binding:

std::function<void(void)> f = std::bind(&A::operator(), &ob);

(See question on using std::function on member functions)

Community
  • 1
  • 1
DarkWanderer
  • 8,739
  • 1
  • 25
  • 56
3

If you use C++11, could use std::function

#include <functional>

std::function<void()> f;

int main()
{
    A ob;
    ob();

    f = ob;    // f refers to ob
    f();       // Call ob();
    return 0;
}
billz
  • 44,644
  • 9
  • 83
  • 100
2

Yes it's kind of possible using a C++1/C++0x feature, but to achieve this you should use the std::function which can address to the two types, functions and object functions.

#include <functional>

 class A
{
public:
    void operator()() { }
};

int main()
{
    std::function<void(void)> aFunction;
    A ob;

    aFunction = ob;

// or as another user said
// aFunction = std::bind(&A:operator(), &ob);

    aFunction();

    void (*f)();

    aFunction = f;

    aFunction();

    return 0;
}

and if you're stuck with C++03, you could play with std::mem_fun and std::ptr_fun

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
1

How about some workaround like this:

Basically you want to have a common way of calling member functions and functions. Then maybe you could create a wrapper that would represent a generic pointer to either a function or member function. Let's say you have Base class and you want to be able to invoke operator() of all derived classes. Then you also have a function() that you want to invoke as well:

class Base
{
public:
    virtual void operator()() = 0;
};

class A : public Base
{
public:
    void operator()(){ std::cout << "A()" << std::endl; }
};

void function()
{
    std::cout << "function" << std::endl; 
}

If you create an wrapper that allows you to construct your custom pointer (MyFncPtr):

typedef void (Base::*BaseFncPtr)();
typedef void (*FncPtr)();

class MyFncPtr
{
public:
    MyFncPtr(FncPtr f) : fnc(f), baseObj(NULL), baseFnc(NULL) { }
    MyFncPtr(BaseFncPtr fPtr, Base* objPtr) : baseFnc(fPtr), baseObj(objPtr), fnc(NULL)  { }
    void invoke()
    {
        if (baseObj && baseFnc)
            (baseObj->*baseFnc)();
        else if (fnc)
            fnc();
    }

private:
    BaseFncPtr baseFnc;
    Base* baseObj;
    FncPtr fnc;
};

you could achieve it like this:

A a;
MyFncPtr myPtr(&Base::operator(), &a);
myPtr.invoke();
MyFncPtr myPtr2(function);
myPtr2.invoke();

outputs:

A()
function

Hope this helps :)

LihO
  • 41,190
  • 11
  • 99
  • 167
  • Just note that it's rather concept that final solution. You should consider problem with dangling pointers when you still keep the `MyPtr` object once the original `baseObj` is destructed, etc. Smart pointers could be used so that it becomes more proper solution :) – LihO Feb 01 '13 at 10:42
  • +1 for workaround which works without the new C++11 features. Thank you! – Jacob Krieg Feb 02 '13 at 23:02
  • @JohnSmith: You're welcome :) Yeah, I wanted to point out that there are other solutions than those relying on C++0x/C++11 ;) – LihO Feb 02 '13 at 23:06