void flip(F f, T1 &&t1, T2 &&t2) {

 f(std::forward(t2), std::forward(t1));

}

Если происходит вызов функции flip(g, i, 42), то параметр i будет передан функции g(), поскольку int& и 42 будут переданы как int&&.

Подобно функции std::move(), для функции std::forward() не стоит предоставлять объявление using. Причина описана в разделе 18.2.3.

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

Упражнение 16.47. Напишите собственную версию функции обращения и проверьте ее, вызывав функции с параметрами ссылок на r-значение и l-значение.

<p><image l:href="#books.png"/>16.3. Перегрузка и шаблоны</p>

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

На подбор функции (см. раздел 6.4) присутствие шаблона функции влияет следующими способами.

• В набор функций-кандидатов на вызов включаются любые экземпляры шаблона функции, для которой успешна дедукция аргумента шаблона (см. раздел 16.2).

• Шаблоны функций-кандидатов всегда подходящие, поскольку дедукция аргумента шаблона устранит все неподходящие шаблоны.

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

• Так же как обычно, если только одна функция обеспечивает наилучшее соответствие, она и выбирается. Но если одинаково хорошее соответствие обеспечивают несколько функций, то:

  • если в наборе одинаково хороших соответствий есть только одна нешаблонная функция, то выбрана будет она;

  • если в наборе нет нешаблонных функций, но есть несколько шаблонных, и одна из них более специализированна, чем любые другие, то будет выбран более специализированный шаблон функции;

  • в противном случае вызов неоднозначен.

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

Создание перегруженных шаблонов

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

// выводит любом тип, который иначе не обработать

template string debug_rep(const T &t) {

 ostringstream ret; // см. раздел 8.3

 ret << t; // использует оператор вывода Т для вывода представления t

 return ret.str(); // возвращает копию строки, с которой связан ret

}

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

Теперь определим версию функции debug_rep() для вывода указателя:

// выводит указатели как их значение, сопровождаемое объектом,

// на который он указывает

// обратите внимание: эта функция не будет работать правильно с char*;

// см. раздел 16.3

template string debug_rep(T *p) {

 ostringstream ret;

 ret << "pointer: " << p; // выводит собственное значение указателя

 if (p)

  ret << " " << debug_rep(*p); // выводит значение, на которое

                               // указывает p

 else

  ret << " null pointer"; // или указывает, что p - нулевой

 return ret.str(); // возвращает копию строки, с которой связан ret

}

Эта версия создает строку, содержащую собственное значение указателя и вызывает функцию debug_rep() для вывода объекта, на который указывает этот указатель. Обратите внимание, что эта функция не может использоваться для вывода символьных указателей, поскольку библиотека ввода-вывода определяет версию оператора << для значения указателя char*. Эта версия оператора << подразумевала, что указатель обозначает символьный массив с нулевым символом в конце и выводит содержимое массива, а не его адрес. Обработка символьных указателей рассматривается в разделе 16.3.

Эти функции можно использовать следующим образом:

string s("hi");

cout << debug_rep(s) << endl;

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

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