Поскольку тип возвращаемого значения указан после списка параметров, проще заметить, что функция func() возвращает указатель и что этот указатель указывает на массив из десяти целых чисел.

Использование спецификатора decltype

В качестве другой альтернативы, если известен массив (массивы), указатель на который способна возвратить наша функция, можно использовать спецификатор decltype, чтобы объявить тип возвращаемого значения. Например, следующая функция возвращает указатель на один из двух массивов, в зависимости от значения ее параметра:

int odd[] = {1,3,5,7,9};

int even[] = {0,2,4,6,8};

// возвращает указатель на массив из пяти элементов типа int

decltype(odd) *arrPtr(int i) {

 return (i % 2) ? &odd : &even // возвращает указатель на массив

}

Тип возвращаемого значения функции arrPtr() указан как decltype, свидетельствуя о том, что функция возвращает указатель на любой тип, который имеет odd. В данном случае этот объект является массивом, поэтому функция arrPtr() возвращает указатель на массив из пяти целых чисел.

Единственная сложность здесь в том, что следует помнить, что спецификатор decltype не преобразовывает автоматически массив в указатель соответствующего ему типа. Тип, возвращенный спецификатором decltype, является типом массива, для которого нужно добавить *, чтобы указать, что функция arrPtr() возвращает указатель.

Упражнения раздела 6.3.3

Упражнение 6.36. Напишите объявление функции, возвращающей ссылку на массив из десяти строк, не используя ни замыкающий тип возвращаемого значения, ни спецификатор decltype или псевдоним типа.

Упражнение 6.37. Напишите три дополнительных объявления для функций предыдущего упражнения. Нужно использовать псевдоним типа, замыкающий тип возвращаемого значения и спецификатор decltype. Какую форму вы предпочитаете и почему?

Упражнение 6.38. Перепишите функцию arrPtr() так, чтобы она возвращала ссылку на массив.

<p><image l:href="#reader.png"/>6.4. Перегруженные функции</p>

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

void print(const char *cp);

void print(const int *beg, const int *end);

void print(const int ia[], size_t size);

Эти функции выполняют одинаковое действие, но их параметры относятся к разным типам. При вызове такой функции компилятор принимает решение о применении конкретной версии на основании типа переданного аргумента:

int j[2] = {0, 1};

print("Hello World");        // вызов print (const char*)

print(j, end(j) - begin(j)); // вызов print(const int*, size_t)

print(begin(j), end(j));     // вызов print(const int*, const int*)

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

Функция main() не может быть перегружена.

Определение перегруженных функций

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

Record lookup(const Account&); // поиск по счету

Record lookup(const Phone&);   // поиск по телефону

Record lookup(const Name&);    // поиск по имени

Account acct;

Phone phone;

Record r1 = lookup(acct);  // вызов версии, получающей Account

Record r2 = lookup(phone); // вызов версии, получающей Phone

Здесь у всех трех функций одинаковое имя, но все же это три разные функции. Чтобы выяснить, которую из них вызвать, компилятор использует тип (типы) аргументов.

Перегруженные функции должны отличаться по количеству или типу (типам) своих параметров. Каждая из функций выше получает один параметр, но типы у этих параметров разные.

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

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