Синтаксис сигнатуры функции-члена C ++ typedef - PullRequest
23 голосов
/ 28 января 2011

Я хочу объявить определение типа для сигнатуры функции-члена. Глобальные функции typedefs выглядят так:

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

Но я не могу сделать то же самое для функции-члена:

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

Это звучит логично для меня, потому что "foo ::" это синтаксис для доступа к члену в классе foo. Как я могу печатать только подпись?

Ответы [ 5 ]

11 голосов
/ 29 января 2011

Для вопросов относительно синтаксиса указателя на неудобные функции я лично использую шпаргалку: Учебное пособие по указателям на функции ( можно загрузить здесь , благодаря Vector для указывая на это).

Однако, как вы уже видели, подпись функции-члена немного отличается от подписи обычной функции.

Как вы, вероятно, знаете, функция-член имеет скрытый параметр this, тип которого необходимо указать.

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

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

позволяет вам указать, что первый элемент, переданный функции, будет Foo* (и, таким образом, ваш метод действительно принимает 3 аргумента, когда вы об этом думаете, а не только 2.

Однако есть и другая причина, заставляющая вас указать тип.

Указатель на функцию может ссылаться на виртуальную функцию, и в этом случае все может быть довольно сложно. Следовательно, размер представления в памяти изменяется в зависимости от типа функции. Действительно, в Visual Studio размер указателя на функцию может варьироваться от 1 до 4 раз больше размера обычного указателя. Это зависит от того, является ли функция виртуальной, в частности.

Следовательно, класс, к которому относится функция , является частью сигнатуры , и обходного пути нет.

6 голосов
/ 27 июля 2015

Вы можете выделить целевой класс в современном C ++ (пост 11), используя «typedefing» качества из шаблонных псевдонимов . То, что вам нужно, будет выглядеть так:

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

Тем не менее, в точке объявления указатель на функцию-член, использующий этот синтаксис, должен был бы указать целевой класс:

// D is a member function taking (int, int) and returning int
memberf_pointer<foo> mp = &foo::D; 
2 голосов
/ 29 января 2011

у меня работает:

#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 ;
  }
1 голос
/ 28 января 2011

Причина, по которой он не работает с вашим текущим синтаксисом, заключается в том, что приоритет оператора диктует, что вы ссылаетесь на функцию с именем foo::memberf_signature, а не на какой-либо тип.

Я не знаю дляконечно, можете ли вы сделать это или нет, но я не смог придумать комбинацию скобок, которая побудила бы код скомпилироваться с g ++ 4.2.

0 голосов
/ 28 января 2011

Ну, в принципе, это не может работать (по крайней мере, я не знаю, как использовать g ++); При использовании компилятора borland c ++ было бы ключевое слово __closure.

Причина, по которой он не компилируется, состоит в том, что размер указателя функции (на компьютере с архитектурой x86) всегда занимает << 32bit >>; но если вы хотите указать на сигнатуру класса (интерфейса), размер должен быть 64-битным: 32-битный для указателя this (так как интерфейс класса находится в памяти только один раз) и 32-битный для фактической функции

Но ключевое слово __closure - это не стандартизированный взлом языка bcb ...

...