syntax for "pointer-to-member" as return value type

I am so close to understanding pointer-to-member, but I'm lost on the syntax to have it as a return value type.

Using a typedef I managed to make it work.
I used "Zz" to alias a pointer-to-member type. If I put this alias as a return value type in a function, the code works as intended.

But what I like to know is, without using a typedef-alias, what code could replace the word "Zz" and still make the code work?
If I try something like int (Calculator::*)(int,int) I get error:
expected unqualified-id
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>

using namespace std;

class Calculator;

typedef int(Calculator::*Zz)(int,int);

class Calculator {
public:
    int add(int x, int y) { return x+y; };
    int subtract(int x, int y) { return x-y; }
    int multiply(int x, int y) { return x*y; }
    int devide(int x, int y) {return x/y; }
};

Zz perform(string function) {
    if (function == "add") return &Calculator::add;
    if (function == "subtract") return &Calculator::subtract;
    if (function == "multiply") return &Calculator::multiply;
    if (function == "devide") return &Calculator::devide;
    else return &Calculator::add;
}

void print(string function, int x, int y) {
    Calculator c;
    int (Calculator::*cp)(int,int) = perform(function);
    cout << (c.*cp)(x,y) << endl;
}

int main() {
    print("add", 6, 2);
    print("subtract", 6, 2);
    print("multiply", 6, 2);
    print("devide", 6, 2);
}


8
4
12
3


Just like your typedef, the name of the function (perform, in this case) needs to go next to the Calculator::* part.
int (Calculator::*perform(string function))(int,int) {
You really ought to leave it as a typedef though, for readability, heh.
Thanks!! That did the trick.
yeah, typedef would surely make it a hell of a lot easier to read.
Ok, so I experimented some more with my code. I changed my functions into member functions, some of which are static and tried to make the print function without creating temporary object "c" in the print function.

I got it to work for 99%.. Only the cout function is refusing.. the old code for print won't do it anymore either (cause I changed my pointer-to-member into static?)

Is there a way to rewrite the cout function, by calling the right function using cp?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

using namespace std;
    
class Calculator {
    //members
    static int (Calculator::*cp)(int,int);
    static int(Calculator::*perform(string function))(int,int);
    
    //member functions
    int add(int x, int y) { return x+y; };
    int subtract(int x, int y) { return x-y; }
    int multiply(int x, int y) { return x*y; }
    int devide(int x, int y) {return x/y; }
public:
    friend void print(string function, int x, int y);
};

int (Calculator::*Calculator::cp)(int,int) = &Calculator::add;
    
    
int(Calculator::*Calculator::perform(string function))(int,int) {
    if (function == "add") return &Calculator::add;
    if (function == "subtract") return &Calculator::subtract;
    if (function == "multiply") return &Calculator::multiply;
    if (function == "devide") return &Calculator::devide;
    else return &Calculator::add;
}
    
void print(string function, int x, int y) {
    Calculator::cp = Calculator::perform(function);
    cout << (Calculator::*cp)(x,y) << endl; //Expected unqualified id
}


int main() {
    print("add", 6, 2);
    print("subtract", 6, 2);
    print("multiply", 6, 2);
    print("devide", 6, 2);
}
The add, subtract,multiply and devide functions are non-static member functions.
You can only call these functions on an object of the appropriate type.
1
2
3
4
5
6
7
8
void print(string function, int x, int y) 
{
    Calculator::cp = Calculator::perform(function);
    
    Calculator an_object;  
    
    cout <<  (an_object.*Calculator::cp)(x,y) << endl; 
}



p.s we know what you mean - but divide not devide
If i can add my 1 cent worth:

You should check for divide by zero
Thanks.

(1)
I see, but does that mean there is no way around creating a temporary object? I was trying to find out if there is a way to avoid creating any object at all.

(2)
When I make my add/divide* (*thanks) functions static they can't be returned. Why can't they be returned if I make them static?

line 19, 23-27 in my last version create the following error when making those static:
Cannot initialize a variable of type 'int (Calculator::*)(int,int)' with an rvalue of type 'int (*)(int, int)'
Last edited on
I see, but does that mean there is no way around creating a temporary object? I was trying to find out if there is a way to avoid creating any object at all.

The whole point of pointer_to_non_static_member_function is
that you need a object or at least a pointer to an object - see my disclaimer below.

Disclaimer:
there is a (dangerous) way around the statement I have made above - in
that someone looking at the way your calculator class is written, would
notice that your math functions do not make use of any calculator class member variables.
This person would then do the following shortcut so as not to have to
create a calculator variable.
1
2
3
4
5
6
7
8
void print(string function, int x, int y) 
{
    Calculator::cp = Calculator::perform(function);
    
    //Calculator an_object; //not needed
    
    cout <<  ( ((Calculator*)0)->*Calculator::cp)(x,y) << endl; 
}


But this approach is not recommended, because that person can not know
how the calculator class code might change in the future and might
have big problems (crashes).


Wow, that's very clever, I see.

I wasn't aware the pointer is supposed to only point to non-static-member-functions.
Do you happen to know why that is?

if I would change add, subtract, etc.. into static members, aren't they getting an address, which could be pointed to (in theory?)

(Thanks for all your time and thorough explanation so far!!)
static_member_functions do not have a this pointer - so pointer_to static_member_functions have the same syntax as for normal pointer_to_functions Which also means that static member functions CANNOT access non-static class variables

Notice the difference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using namespace std;
    
class Calculator {
    //members
    static int (*cp)(int,int);
    static int(*perform(string function))(int,int);
    
    //member functions
     static int add(int x, int y) { return x+y; };
     static int subtract(int x, int y) { return x-y; }
     static int multiply(int x, int y) { return x*y; }
     static int devide(int x, int y) {return x/y; }
public:
    friend void print(string function, int x, int y);
};

int (*Calculator::cp)(int,int) = &Calculator::add;
    
    
int(*Calculator::perform(string function))(int,int) {
    if (function == "add") return &Calculator::add;
    if (function == "subtract") return &Calculator::subtract;
    if (function == "multiply") return &Calculator::multiply;
    if (function == "devide") return &Calculator::devide;
    else return &Calculator::add;
}
    
void print(string function, int x, int y) 
{
    Calculator::cp = Calculator::perform(function);
    
    cout <<  Calculator::cp(x,y) << endl; 
}


int main() {
    print("add", 6, 2);
    print("subtract", 6, 2);
    print("multiply", 6, 2);
    print("devide", 6, 2);
}
Aaaah, ok that's an eye-opener. I got completely on the wrong foot in my assumption why the code wasn't running with statics.

One more thing that confuses me.
Why does making the functions static change the type to int(*)(int,int) and when it's non-static it's considered int(Calculator::*)(int,int)

This is what's happening right?
Really hope someone could answer that last statement. Do I understand it correctly?
Prestissimo wrote:
One more thing that confuses me.
Why does making the functions static change the type to int(*)(int,int) and when it's non-static it's considered int(Calculator::*)(int,int)


as you know, static members exist without having to be associated with an object of the class (which means they don't need or indeed have a this pointer).

This means that they are like standard C++ items and therefore uses standard C++ pointers.

Another thing is that the non-staticc_member_pointer which
is declared like this (for example)
int(Calculator::* some_pointer)(int,int)
will at some point HAVE TO BE associated with an object of the appropriate class type before you can dereference the pointer.
Like this:

1
2
3
4
int(Calculator::* some_pointer)(int,int); //
Calculator cc;  
some_pointer = & Calculator::subtract;
 int result = (cc.*some_pointer)(4,3); //necessary for non_static_member pointer - ERROR for static_member pointer 



EDIT
One thing I must add, that might confuse you even more, is that structures
are a carry over from C and C did not have the concept
of a pointer_to_member and just used normal pointers.

This means that in C++, you can have :

1
2
3
4
5
6
7
8
9
class MyClass
{
   public:
   int  x;
};

MyClass mc; //object of my class
int * pi;   //normal pinter to int.
pi =& mc.x;  


Last edited on
Thanks, that last example makes it even more clear. I messed around some more and i think I finally get it. A very big thank you for your explanation!
Topic archived. No new replies allowed.