views:

196

answers:

4

In Bjarne Stroustrup's home page (C++0x FAQ):

struct X { int foo(int); };

std::function<int(X*, int)> f;
f = &X::foo; //pointer to member

X x;
int v = f(&x, 5); //call X::foo() for x with 5

How it works? How std::function calls foo member function?

According to the template parameter int(X*, int), is &X::foo converted from the member function pointer to a non-member function pointer?!

(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))

To be more clarify: I know that we don't need to cast any pointer for using std::function, but i don't know that what is the internals of std::function to handle this incompatibilities between member function pointer and non-member function pointer? I don't know how the standard allows us to implement something like std::function!

A: 

They're not function pointers. That's what std::function exists for. It wraps whatever callable types you give it. You should check out boost::bind- it's often used to make member function pointers callable as (this, args).

DeadMG
Tyler McHenry
boost::bind not good enough?
DeadMG
+1  A: 

How it does it (I believe) is left undefined (but I don't have a copy of the standard here).

But given all the different posabilities that need to be covered I have the feeling that deciphering the exact definition of how it works would be really hard: So I am not going to try.

But I think you would like to know how functors work and they are relatively simple. So here is a quick example.

Functors:

These are objects that act like functions.
They are very uefull in template code as they often allow you to use objects or functions interchangebly. The great thing about functors though is that they can hold state (a sort of poor mans closure).

struct X
{
     int operator()(int x) { return doStuff(x+1);}
     int doStuff(int x)    { return x+1;}
};

X   x;  // You can now use x like a funtion
int  a = x(5);

You can use the fact that functor hold state to hold things like parameters or the objects or the pointer to member methods (or any cobination therof).

struct Y // Hold a member function pointer
{
    int (X::*member)(int x);
    int operator(X* obj, int param) { return (obj->*member)(param);}
};
X  x;
Y  y;
y.member = &X::doStuff;
int a = y(&x,5);

Or even go further and bind parameters. So now all you need to provide is one of the parameters.

struct Z
{
    int (X::*member)(int x);
    int  param;
    Z(int (X::*m)(int), int p) : member(m), param(p) {}

    int operator()(X* obj)  { return (obj->*member)(param);}
    int operator()(X& obj)  { return (obj.*member)(param);}
};

Z z(&X::doStuff,5);

X x;
int a = z(x);
Martin York
Thanks for the info, although i know what a functor (function object) is, and i tried to know : "How the std::function holds/calls a member/non-member function pointer?" and i couldn't.
PC2st
It probably uses a whole host of template specializations. But holding a function pointer is no different to holding a method pointer it is just the types that are different.
Martin York
+1  A: 

g++ seems to have an union which may keep either function pointer, member pointer or void pointer which probably points to a functor. Add overloads which appropriately flag which union member is valid and heavy casting to a soup and then it works...

Tomek
Thanks, i believe that casting _member function pointer_ to _non-member function pointer_ is left undefined behavior! and by using an union, no cast is needed. i should test it. but how the members of this union is detectable by only one template parameter (we just specify one function type for std::function)?
PC2st
+1  A: 

Thanks for all answers.

I found a good example from section 14.8.2.5-21 of the standard:

template<class> struct X { };
template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };
template<class ... Types> struct Y { };
template<class T, class ... Types> struct Y<T, Types& ...> { };
template<class ... Types> int f(void (*)(Types ...));
void g(int, float);
// uses primary template
X<int> x1;
// uses partial specialization; ArgTypes contains float, double
X<int(int, float, double)> x2;
// uses primary template
X<int(float, int)> x3;
// use primary template; Types is empty
Y<> y1;
// uses partial specialization; T is int&, Types contains float, double
Y<int&, float&, double&> y2;
// uses primary template; Types contains int, float, double
Y<int, float, double> y3;
// OK; Types contains int, float
int fv = f(g);

It says that with template specialization, we can parse template parameters of a function type (awesome)! The following is a dirty/simple example about how std::function can work:

template<class T> struct Function { };

template<class T, class Obj, class... Args>
struct Function<T(Obj*, Args...)> // Parsing the function type
{
    enum FuncType
    {
        FuncTypeFunc,
        FuncTypeMemFunc
    };
    union FuncPtr
    {
        T(*func)(Obj*, Args...);
        T(Obj::*mem_func)(Args...);
    };

    FuncType m_flag;
    FuncPtr m_func_ptr;

    Function(T(*func)(Obj*, Args...)) // void(*)(Funny*, int, int)
    {
        m_flag = FuncTypeFunc;
        m_func_ptr.func = func;
    }
    Function(T(Obj::*mem_func)(Args...)) // void(Funny::*)(int, int)
    {
        m_flag = FuncTypeMemFunc;
        m_func_ptr.mem_func = mem_func;
    }

    void play(Obj* obj, Args... args)
    {
        switch(m_flag)
        {
          case FuncTypeFunc:
            (*m_func_ptr.func)(obj, args...);
            break;
          case FuncTypeMemFunc:
            (obj->*m_func_ptr.mem_func)(args...);
            break;
        }
    }
};

Usage:

#include <iostream>

struct Funny
{
    void done(int i, int j)
    {
        std::cout << "Member Function: " << i << ", " << j << std::endl;
    }
};

void done(Funny* funny, int i, int j)
{
    std::cout << "Function: " << i << ", " << j << std::endl;
}

int main(int argc, char** argv)
{
    Funny funny;
    Function<void(Funny*, int, int)> f = &Funny::done; // void(Funny::*)(int, int)
    Function<void(Funny*, int, int)> g = &done; // void(*)(Funny*, int, int)
    f.play(&funny, 5, 10); // void(Funny::*)(int, int)
    g.play(&funny, 5, 10); // void(*)(Funny*, int, int)
    return 0;
}

Edit: Thanks to Tomek for his good hint about unions, the above example is changed to hold the member/non-member function pointer in one (not two) variable.


Edit: Martin York is right, the switch statement wasn't a good idea in the above example, so i changed the example completely to work better, the following isn't dirty anymore :-)

template<class T> class Function { };

template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> // Parsing the function type
{
    union Pointers // An union to hold different kind of pointers
    {
        Res (*func)(Obj*, ArgTypes...); // void (*)(Funny*, int)
        Res (Obj::*mem_func)(ArgTypes...); // void (Funny::*)(int)
    };
    typedef Res Callback(Pointers&, Obj&, ArgTypes...);

    Pointers ptrs;
    Callback* callback;

    static Res call_func(Pointers& ptrs, Obj& obj, ArgTypes... args)
    {
        return (*ptrs.func)(&obj, args...); // void (*)(Funny*, int)
    }
    static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args)
    {
        return (obj.*(ptrs.mem_func))(args...); // void (Funny::*)(int)
    }

  public:

    Function() : callback(0) { }
    Function(Res (*func)(Obj*, ArgTypes...)) // void (*)(Funny*, int)
    {
        ptrs.func = func;
        callback = &call_func;
    }
    Function(Res (Obj::*mem_func)(ArgTypes...)) // void (Funny::*)(int)
    {
        ptrs.mem_func = mem_func;
        callback = &call_mem_func;
    }
    Function(const Function& function)
    {
        ptrs = function.ptrs;
        callback = function.callback;
    }
    Function& operator=(const Function& function)
    {
        ptrs = function.ptrs;
        callback = function.callback;
        return *this;
    }
    Res operator()(Obj& obj, ArgTypes... args)
    {
        if(callback == 0) throw 0; // throw an exception
        return (*callback)(ptrs, obj, args...);
    }
};

Usage:

#include <iostream>

struct Funny
{
    void print(int i)
    {
        std::cout << "void (Funny::*)(int): " << i << std::endl;
    }
};

void print(Funny* funny, int i)
{
    std::cout << "void (*)(Funny*, int): " << i << std::endl;
}

int main(int argc, char** argv)
{
    Funny funny;
    Function<void(Funny*, int)> wmw;

    wmw = &Funny::print; // void (Funny::*)(int)
    wmw(funny, 10); // void (Funny::*)(int)

    wmw = &print; // void (*)(Funny*, int)
    wmw(funny, 8); // void (*)(Funny*, int)

    return 0;
}
PC2st
One would hate to think there was a switch statement buried inside this code.
Martin York
@Martin York: Thanks, i changed it.
PC2st