1

Hello this is an update of this previous question i did

I was trying to execute a function by pointer inside a class (the class content is not relevant to the problem I am having).

This was the code posted on the previous question:

error message:

cannot convert ‘Clip::func’ from type ‘void (Clip::)(std::string) {aka void (Clip::)(std::basic_string<char>)}’ to type ‘callback {aka void (*)(std::basic_string<char>)}’

Clip.h

void func(string str){
    cout << str << endl;
}

Clip.cpp

void Clip::update(){
    typedef void(*callback)(string);
    callback callbackFunction = func;
    callbackFunction("called");
}

------The solution i found------


Me and a friend did some quick research to find a way to get around this situation and this is what we found. Even though this works, we have some doubts about the expresios involved (questions at the end of the post)

Clip.h

    typedef  void (Clip::*Callback) (string);
    void func(string _val);

Clip.cpp

void Clip::update(){
    Callback function;
    function = &Clip::func;
    (this->*function)("a");
}

Questions:

a- in the previous post @tkausl answered: "...Member function pointers are not compatible with (non-member) function pointers". Is that the reason why the other code does not work inside of any class (even if that class is completely empty)?

b- why is it necessary to declare the pointer like thi: Clip::*Callback if we are already inside of the Clip class?

c- What does this expression mean?: this->*function

d- is there an easier way or expression for this same requierement?

thanks in advance.

udiskie
  • 15
  • 6
  • I feel like you haven't grasp the difference between a member function pointer and a regular function pointer. Remember that non-static member functions *need* and instance on which to be called. You couldn't call `Clip::func` any more than you could assign `Clip::func` to a `void(*)(string)`. Which instance would it call it on? – François Andrieux Jul 17 '18 at 18:57
  • [This question](https://stackoverflow.com/questions/2402579/function-pointer-to-member-function) sounds like a duplicate, but I'm not it's what you are actually asking. – François Andrieux Jul 17 '18 at 18:58

2 Answers2

1

You've indeed encountered pointers to member functions. They're similar to ordinary function pointers, but more nuanced, because (non-static) member functions always implicitly have a special this parameter passed to them that refers to the current object on which the function was invoked. That secret this parameter is strongly typed according to the class containing the function. That's why the class name is also part of a pointer to member function's type. It's also the reason they don't mix with regular function pointers. Here's a basic example:

// Declaration of a pointer to member function
// Note that no object is used here
void (ClassName::*my_fn_pointer)(ParameterTypes);

// Assignment also doesn't use an object
my_pointer = &ClassName::exampleMemberFunction;

// But to invoke the method, you need an object
ClassName obj;
(obj::*my_fn_pointer)(example_params);

// Alternatively, inside a member function of ClassName:
(this->*my_fn_pointer)(example_params);

There are plenty of alternatives. I can't see the rest of your code and what problem you're trying to solve and so my advice is limited. I would however endorse using std::function with lambdas:

// std::function generically wraps a callable type
std::function<void(ParamTypes)> my_fn;


// Using an object:
ClassName obj;
// lambda declaration
my_fn = [&obj](ParamTypes params){
    // 'obj' is captured by reference, so make sure it stays alive as long as needed
    obj.chooseYourMemberFunctionHere(params);
};

// function is called here, syntax is easier on the eyes
my_fn(example_params);


// Using 'this' inside a member function:
my_fn = [this](ParamTypes params){
    // 'this' is captured by reference
    // also make sure the current object stays alive alive as long as needed
    this->chooseYourMemberFunctionHere(params);
};

my_fn(example_params); // function is called here
alter_igel
  • 6,899
  • 3
  • 21
  • 40
0

A

It has nothing to do with where you write your code. Member function pointer and function pointers are two different types of pointers. Your code doesn't work because you cannot assign a member function pointer to normal function pointer. Had it been possible consider this piece of code, what should be its output?

class Foo
{
public:
    Foo(int x) :x(x) {}
    void bar(int y)
    {
        std::cout << x+y;
    }
    int x;
}
int main()
{
    typedef void(*callback)();

    callback ptr = &Foo::bar;//Won't compile with same error as in your question

    ptr(5);
}

There's no instance of Foo so there's no x to print. Unlike C# the C++ won't let you capture this, so Foo f; callback ptr = &f::bar won't compile either. You can think about Foo::bar being equivalent to

void bar(Foo* this,int y)
{
   std::cout<< this->x+y;
}

And now you see those function types are really different.

B

You can see from above bar translation that type of this has to be specified it doesn't matter where you write that code.

C

Calling a member function is done via ->* operator, its left-hand side is exactly the missing this pointer and right-hand side is a member function pointer variable and the arguments. See:

Foo foo;
typedef void(Foo::callback)(int);//Member pointer
callback ptr = &Foo::bar;//Now OK
Foo* thisFoo = &foo;//Left-hand side must be a pointer to Foo
(thisFoo->*ptr)(5);//equivalent to foo->bar(5);

this->*function Just means call a member function stored in function variable and use this pointer as the instance.

D

What requirement? The conversion cannot be done. There's a hacky way with template functions and local static variables that works if you know that at every moment there will only be one callback assigned per type. Otherwise try to not use them, there are safer alternatives with lambdas and std::function available that can bind this in c# fashion. link

Community
  • 1
  • 1
Quimby
  • 17,735
  • 4
  • 35
  • 55