Синтаксис сигнатуры функции-члена 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...