38

I want to declare type definition for a member function signature. Global function typedefs look like this:

typedef int (function_signature)(int, int);
typedef int (*function_pointer) (int, int);

But I'm not able to the same thing for a member function:

typedef int (foo::memberf_signature)(int, int);   // memberf_pointer is not a member of foo
typedef int (foo::*memberf_pointer)(int, int);

It sounds logically to me, because foo:: is the syntax to access a member in the class foo.

How can I typedef just the signature?

user3840170
  • 26,597
  • 4
  • 30
  • 62
0xbadf00d
  • 17,405
  • 15
  • 67
  • 107

5 Answers5

31

For questions regarding the awkward function pointer syntax, I personally use a cheat-sheet: The Function Pointers Tutorial (downloadable here, thanks to Vector for pointing it out).

The signature of a member function, however, is a bit different from the signature of a regular function, as you experienced.

As you probably know, a member function has a hidden parameter, this, whose type need be specified.

// C++11 and above.
using Member = int (Foo::*)(int, int);

// C++03 and below.
typedef int (Foo::*Member)(int, int);

does let you specify that the first element passed to the function will be a Foo* (and thus your method really takes 3 arguments, when you think of it, not just 2.

However there is another reason too, for forcing you to specify the type.

A function pointer might refer to a virtual function, in which case things can get quite complicated. Therefore, the very size of the in-memory representation changes depending on the type of function. Indeed, on Visual Studio, a function pointer's size might vary between 1 and 4 times the size of a regular pointer. This depends on whether the function is virtual, notably.

Therefore, the class the function refers to is part of the signature, and there is no work-around.

Alexis Evelyn
  • 304
  • 5
  • 17
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • @BЈовић: and it was such a good link too... oh well thankfully I knew a second article ;) – Matthieu M. Oct 25 '12 at 14:24
  • New working link with _downloads_ for [**The Function Pointers Tutorial**](http://www.newty.de/fpt/dload.html) – Vector Feb 14 '15 at 04:44
  • How would this look with C++11 "using" syntax? – paulm May 26 '19 at 18:07
  • 1
    @paulm: Good question, post edited. It's basically the same, except the name is extracted, and thus easier to find. – Matthieu M. May 26 '19 at 18:12
  • @MatthieuM. Is this valid? Are you sure that the type of a non-static member function/data (not the type of a member pointer to that function/data) is `Return(Class::*)(Args...)` and not `Return(Class::)(Args...)`? If so, then is it true that `this*` is the reason for the `*` in the member's or member pointer's identical type (iow the fact that `this*` is a **"pointer"** that's always part of the signature)? – KeyC0de Sep 22 '19 at 17:44
  • 1
    @Nikos: You can try the syntax yourself in a compiler: `Return(Class::)(Args...)` is not valid syntax. `this` (not `this*`) is always a pointer, despite never being null, and is passed as a pointer to methods. The invocation syntax is `(this->*method)(args...)` or `(ref.*method)(args...)`, which is another layer of weird... – Matthieu M. Sep 22 '19 at 17:51
  • Can you elaborate a bit more? In the next 3 examples `A`, `B` and `C` compile but not `D`. `template using A = int (T::*)(A...); template using B = void (T::*)(A...); template using C = int T::*; template using D = void T::*; ` – Patrick Fromberg Jan 26 '23 at 02:07
  • @PatrickFromberg: C and D are NOT function pointers (and thus outside this question), they are pointers to data-members. Different syntax, and a data-member cannot have for type `void` thus D is wrong. – Matthieu M. Jan 26 '23 at 07:52
  • @MatthieuM. Yes, this is why I was surprised to see pointer to member used as parameter type for functions here: `template< class M, class T> mem_fn(M T::* pm) noexcept`. I was trying to figure out how `std::invoke` works exactly and it works for void returning functions. I should create a dedicated question actually. – Patrick Fromberg Jan 27 '23 at 09:55
8

You can factor out the target class in modern C++ (post 11) by utilizing the 'typedefing' qualities of template aliases. What you need would look like like:

template<typename T>
using memberf_pointer = int (T::*)(int, int); 

Yet at the point of declaration, a pointer to member function utilizing this syntax would need to specify the target class:

// D is a member function taking (int, int) and returning int
memberf_pointer<foo> mp = &foo::D; 
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
1

The reason it doesn't work with your current syntax is that operator precedence dictates that you're referring to a function named foo::memberf_signature, not any sort of type.

I don't know for sure if you can do this or not, but I couldn't come up with any combination of parenthese that induced the code to compile with g++ 4.2.

Mark B
  • 95,107
  • 10
  • 109
  • 188
1

It works for me:

#include <iostream>

class foo
  {
public:
  int g (int x, int y) { return x + y ; }
  } ;

typedef int (foo::*memberf_pointer)(int, int);

int main()
  {
  foo f ;
  memberf_pointer mp = &foo::g ;
  std::cout << (f.*mp) (5, 8) << std::endl ;
  }
TonyK
  • 16,761
  • 4
  • 37
  • 72
  • 2
    That's a typedef for a member function pointer. That work's for me too, but isn't what I'm after ;) – 0xbadf00d Jan 29 '11 at 07:42
  • OK, now I see what you want. But how do you plan to use this typedef, if you manage to create it? – TonyK Jan 29 '11 at 08:42
-3

Well basically it can't work (at least I know no way using g++); Using borland c++ compiler there would be the __closure keyword.

The reason why it does not compile is, that sizeof the functionpointer (on a x86 machine) occupies always <<32bits>>; but if you want to point to a class (interface) signature, the sizeof has to be 64bit: 32 bit for the this pointer (as the class interface is in the memory only once) and 32 bit for the actual function

But the __closure keyword is a bcb language 'hack' not standardized...

  • The fact that member function pointers and function pointers are of different sizes looks irrelevant to me. Typically, `short` and `double` are of different sizes, but you can `typedef` with both of them. – David Thornley Jan 28 '11 at 20:48
  • 1
    The `this` pointer is normally passed as a first, hidden parameter. I haven't heard of any compiler using a 64-bit pointer to munge the this pointer into the pointer to an object. – Timo Geusch Jan 28 '11 at 21:00
  • That's absolutely wrong. The this pointer is stored in the (e.g. MSC) ECX-Register on IA-32 target machine. Any pointer is always 32-bit on such a system. – 0xbadf00d Jan 29 '11 at 07:02