Синтаксис сигнатуры функции-члена C++

Я хочу объявить определение типа для сигнатуры функции-члена. Глобальные функции 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 ответов

Решение

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

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

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

typedef int (Foo::*Member)(int, int);

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

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

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

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

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

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; 

Меня устраивает:

#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 ;
  }

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

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

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

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

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

Другие вопросы по тегам