Указатель на функцию как параметр

Подобно массивам (см. раздел 6.2.4), нельзя определить параметры типа функции, но можно создать параметр, являющийся указателем на функцию. Как и в случае с массивами, можно создать параметр, который выглядит как тип функции, но обрабатывается как указатель:

// третий параметр имеет тип функции и автоматически обрабатывается как

// указатель на функцию

void useBigger(const string &s1, const string &s2,

               bool pf(const string&, const string&));

// эквивалентное объявление: параметр явно определен как указатель

// на функцию

void useBigger(const string &s1, const string &s2,

               bool (*pf)(const string&, const string&));

При передаче функции как аргумента это можно сделать непосредственно. Аргумент будет автоматически преобразован в указатель:

// автоматическое преобразование функции lengthCompare в указатель

// на нее

useBigger(s1, s2, lengthCompare);

Как можно заметить в объявлении функции useBigger(), написание указателей на тип функций быстро становится утомительным. Псевдонимы типа (см. раздел 2.5.1), а также спецификатор decltype (см. раздел 2.5.3) позволяют упростить код, который использует указатели на функции:

// Func и Func2 имеют тип функции

typedef bool Func(const string&, const strings);

typedef decltype(lengthCompare) Func2; // эквивалентный тип

// FuncP и FuncP2 имеют тип указателя на функцию

typedef bool(*FuncP)(const string&, const string&);

typedef decltype(lengthCompare) *FuncP2; // эквивалентный тип

Здесь при определении типов использовано ключевое слово typedef. И Func, и Func2 являются типами функций, тогда как FuncP и FuncP2 — типы указателя. Следует заметить, что спецификатор decltype возвращает тип функции; автоматического преобразования в указатель не происходит. Поскольку спецификатор decltype возвращает тип функции, при необходимости получить указатель следует добавить символ *. Можно повторно объявить функцию useBigger(), используя любой из этих типов:

// эквивалентные объявления useBigger с использованием псевдонимов типа

void useBigger(const string&, const string&, Func);

void useBigger(const string&, const string&, FuncP2);

Оба объявления объявляют ту же функцию. В первом случае компилятор автоматически преобразует тип функции, представленный именем Func, в указатель.

Возвращение указателя на функцию

Подобно массивам (см. раздел 6.3.3), нельзя возвратить тип функции, но можно возвратить указатель на тип функции. Точно так же тип возвращаемого значения следует писать как тип указателя; компилятор не будет автоматически рассматривать тип возвращаемого значения функции как соответствующий тип указателя. Как и при возвращении массива, безусловно, проще всего объявить функцию, которая возвращает указатель на функцию, при помощи псевдонима типа:

using F = int(int*, int);     // F - тип функции, а не указатель

using PF = int(*)(int*, int); // PF - тип указателя

Здесь для определения F как типа функции и PF как указателя на тип функции было использовано объявление псевдонима типа (см. раздел 2.5.1). Имейте в виду, что в отличие от параметров, имеющих тип функции, тип возвращаемого значения не преобразуется автоматически в тип указателя. Следует явно определить, что тип возвращаемого значения является типом указателя:

PF f1(int); // ok: PF - указатель на функцию; f1 возвращает указатель

            // на функцию

F f1(int);  // ошибка: F - тип функции; f1 не может возвратить функцию

F *f1(int); // ok: явное определение типа возвращаемого значения как

            // указателя на функцию

Конечно, функцию f1() также можно объявить непосредственно:

int (*f1(int))(int*, int);

Перейти на страницу:

Похожие книги