- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
При использовании с параметром функции, являющимся ссылкой на r-значение для параметра типа шаблона (Т&&), функция forward() сохраняет все подробности типа аргумента.
Перепишем первоначальную функцию, используя на этот раз функцию forward():
template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2) {
f(std::forward<T2>(t2), std::forward<T1>(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-значение.
16.3. Перегрузка и шаблоны
Шаблоны функций могут быть перегружены другими шаблонами или обычными, не шаблонными функциями. Как обычно, функция с тем же именем должна отличаться либо количеством, либо типом своих параметров.
На подбор функции (см. раздел 6.4) присутствие шаблона функции влияет следующими способами.
• В набор функций-кандидатов на вызов включаются любые экземпляры шаблона функции, для которой успешна дедукция аргумента шаблона (см. раздел 16.2).
• Шаблоны функций-кандидатов всегда подходящие, поскольку дедукция аргумента шаблона устранит все неподходящие шаблоны.
• Как обычно, подходящие функции (шаблонные и нешаблонные) ранжируются по преобразованиям, если таковые вообще имеются. Конечно, набор применимых преобразований при вызове шаблона функции весьма ограничен (см. раздел 16.2.1).
• Так же как обычно, если только одна функция обеспечивает наилучшее соответствие, она и выбирается. Но если одинаково хорошее соответствие обеспечивают несколько функций, то:
• если в наборе одинаково хороших соответствий есть только одна нешаблонная функция, то выбрана будет она;
• если в наборе нет нешаблонных функций, но есть несколько шаблонных, и одна из них более специализированна, чем любые другие, то будет выбран более специализированный шаблон функции;
• в противном случае вызов неоднозначен.
Правильное определение набора перегруженных шаблонов функций требует хорошего понимания отношений между типами и ограничений на преобразования, применимых к аргументам в шаблонах функций.
Создание перегруженных шаблоновВ качестве примера создадим набор функций, которые могли бы пригодиться во время отладки. Назовем отладочные функции debug_rep(), каждая из них возвратит строковое представление предоставленного объекта. Начнем с создания самой общей версии этой функции в качестве шаблона, получающего ссылку на константный объект:
// выводит любом тип, который иначе не обработать
template <typename Т> string debug_rep(const T &t) {
ostringstream ret; // см. раздел 8.3
ret << t; // использует оператор вывода Т для вывода представления t
return ret.str(); // возвращает копию строки, с которой связан ret
}
Эта функция применяется для создания строки, соответствующей объекту любого типа, у которого есть оператор вывода.
Теперь определим версию функции debug_rep() для вывода указателя:
// выводит указатели как их значение, сопровождаемое объектом,
// на который он указывает
// обратите внимание: эта функция не будет работать правильно с char*;
// см. раздел 16.3
template <typename Т> 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;
Подходящей для этого вызова является только первая версия функции debug_rep(). Второй версии требуется параметр в виде указателя, а в этом вызове передан не указатель. Нет никакого способа создать экземпляр шаблона функции, ожидающего тип указателя, из параметра, который не является указателем, поэтому дедукция аргумента терпит неудачу. Поскольку есть только одна подходящая функция, она и используется.
Если происходит вызов функции debug_rep() с указателем:
cout << debug_rep(&s) << endl;
то обе функции создают подходящие экземпляры:
• debug_rep(const string*&) — экземпляр первой версии функции debug_rep() с привязкой параметра Т к типу string*;
• debug_rep(string*) — экземпляр второй версии функции debug_rep() с привязкой параметра Т к типу string.
Точным соответствием для этого вызова является экземпляр второй версии функции debug_rep(). Создание экземпляра первой версии требует преобразования простого указателя в указатель на константу. Обычный подбор функции гласит, что следует предпочесть второй шаблон, и в действительности так и происходит.
Несколько подходящих шаблоновВ качестве другого примера рассмотрим следующий вызов:
const string *sp = &s;
cout << debug_rep(sp) << endl;
Здесь подходящими являются оба шаблона, и оба обеспечивают точное соответствие:
• debug_rep(const string*&) — экземпляр первой версии шаблона с привязкой параметра Т к типу const string*;
• debug_rep(const string*) — экземпляр второй версии шаблона с привязкой параметра Т к типу const string.
В данном случае обычный подбор функции не может различить эти два вызова. Можно было бы ожидать, что этот вызов будет неоднозначен. Однако благодаря специальному правилу для перегруженных шаблонов функций этот вызов решается как debug_rep(Т*), поскольку это более специализированный шаблон.
Причина для этого правила в том, что без него не было бы никакого способа вызвать версию функции debug_rep() для указателя на константу. Проблема в том, что к шаблону debug_rep(const Т&) подходит практически любой тип, включая типы указателя. Этот шаблон является более общим, чем debug_rep(Т*), который может быть вызван только для типов указателя. Без этого правила вызовы с передачей указателей на константу всегда будут неоднозначны.
Когда есть несколько перегруженных шаблонов, предоставляющих одинаково хорошее соответствие для вызова, предпочитается наиболее специализированная версия.
Не шаблон и перегрузка шаблонаДля следующего примера определим обычную, не шаблонную версию функции debug_rep(), выводящую строки в двойных кавычках:
// вывод строк в двойных кавычках
string debug_rep(const string &s) {
return '"' + s + '"';
}
Теперь, когда происходит вызов функции debug_rep() для строки:
string s("hi");
cout << debug_rep(s) << endl;
есть две одинаково хорошо подходящих функции:
• debug_rep<string>(const string&) — первый шаблон с привязкой параметра T к типу string;
• debug_rep(const string&) — обычная, не шаблонная функция.
В данном случае у обеих функций одинаковый список параметров, поэтому каждая из них обеспечивает одинаково хорошее соответствие этому вызову. Однако выбирается нешаблонная версия. По тем же причинам, по которым предпочитаются наиболее специализированные из одинаково хорошо подходящих шаблонов функций, нешаблонная функция предпочитается при одинаково хорошем соответствии с шаблонной функцией.
Когда нешаблонная функция обеспечивает одинаково хорошее соответствие с шаблонной функцией, предпочитается нешаблонная версия.

