Добавил:
t.me Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / Литература / Язык программирования С++. Краткий курс. Страуструп

.pdf
Скачиваний:
9
Добавлен:
16.07.2023
Размер:
31.34 Mб
Скачать

132

Глава

6.

Шаблоны

Механизм

псевдонимов

может

использоваться

для

определения

нового

ша­

блона

путем

связывания

некоторых

или

всех

аргументов

шаблона.

Например:

template<typename

class Мар

{

/ / ...

 

);

 

Кеу,

typename Value>

template<typename

Value>

 

using String_map

= Map<string,Value>;

String_map<int>

m;

//

т представляет

собой

Map<string,int>

6.4.3.

if

времени

компиляции

Рассмотрим

запись

операции,

которая

может

использовать

один

из

двух

ва­

риантов

операции-

slow_and_safe

(Т)

или

simple

and_fast

(Т).

Такие

проблемы

часто

встречаются

в

коде,

где

важны

обобщенность

и

производи­

тельность.

Традиционное

решение

состоит

в

том,

чтобы

написать

пару

пере­

груженных

функций

и

выбирать

наиболее

подходящую

на

основе

свойства

13.9.1

),

такого

как,

например,

свойство

стандартной

библиотеки

is

_pod.

При

использовании

иерархии

классов

базовый

класс

может

обеспечить

об­

щую

операцию

slow_and_safe,

а производный

класс

-

перекрыть

ее

реа­

лизацией simple_and_fast.

В С++17 можно просто использовать

i

f

времени компиляции:

template<typename Т>

 

void

update(T& target)

 

{

 

 

 

11

 

 

if constexpr(is_pod<T>::value)

 

simple_and_fast(target);

//Для

 

else

 

 

slow_and_safe(target);

 

 

11 ...

 

"простых

старых

данных"

is

_pod<T>

-

это

свойство

типа(§

13.9.1

),

которое

говорит

нам

о

том,

мо­

жет ли этот тип быть тривиально копирован. Инстанцируется только выбранная ветвь

if

constexpr.

Это

решение

предлагает

оптимальную

производительность

и

локальность

оптимизации.

и

Что важно, if constexpr не является механизмом манипуляции текстом

не может нарушать обычные правила грамматики, типов и областей види­

мости.

Например:

template<typename void bad(T arg)

Т>

{

7

:Концепты

и

обобщенное

программирование

Программировать

следует

начинать

с

интересных

алгоритмов.

+ +

-Алекс Степанов

Введение Концепты Применение концептов

+

Перегрузка на основе концептов

Корректный код

Определение концептов

Обобщенное программирование

+

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

Абстракции с использованием шаблонов

Вариативные шаблоны

Выражения свертки

+ +

Передача аргументов

Модель компиляции шаблонов Советы

7.1.

Введение

Для

чего

нужны

шаблоны?

Другими

словами,

какие

методы

программиро­

вания

эффективны

при

использовании

шаблонов?

Шаблоны

предлагают

сле­

дующее.

Возможность передавать типы (а также значения и шаблоны) в качестве

аргументов без

потери информации. Это подразумевает отличные воз­

можности для

встраивания, что обеспечивает большие преимущества

для

современных

компиляторов.

7.2.

Концепты

(С++20)

137

Языковая

поддержка

концептов

еще

не

вошла

в

стандарт

ISO

С++,

но

в

настоящее

время

является

технической

спецификацией

ISO [11].

В

настоящее

время

уже

имеются

используемые

реализации,

поэтому

я

рискну

рекомендо­

вать

концепты

в

этой

книге

-

пусть

даже

детали

могут

измениться

и

может

пройти

несколько

лет

до

того,

как

каждый

сможет

использовать

концепты

в

своем

производственном

коде.

7.2.1.

Применение

концептов

Большинство

аргументов

шаблонов

должны

удовлетворять

определенным

требованиям

для

правильной

компиляции

шаблона

и

правильного

функцио­

нирования

сгенерированного

кода.

Таким

образом,

большинство

шаблонов

должны

быть

ограниченными

шаблонами

(§6.2.1

).

Ключевое

слово

t ypename

является

наименее

ограничивающим,

требующим

только

того,

чтобы

аргу­

мент

был

типом.

Обычно

мы

можем

сделать

большее.

Рассмотрим

функцию

sum ()

еще

раз:

ternplate<Sequence

Seq,

Nurn surn(Seq s,

Nurn

v)

NurnЬer

Nurn>

for

(const

 

v+=x;

return v;

auto&

х

s)

Так

код

становится

намного

яснее.

Как

только

мы

определим,

что

означают

понятия

Sequence

и NurnЬer,

компилятор

сможет

отклонить

неверные

вызо­

вы,

просмотрев

только

интерфейс

sum

(),а не

его

реализацию.

Это

улучшит

отчеты об ошибках.

Однако спецификация

интерфейса

sum

()

неполная:

я

"забыл"

сказать,

что

мы

должны

иметь

возможность

суммировать

элементы

Sequence

с

NumЬer.

Мы

можем

это

сделать:

ternplate<Sequence Seq, NurnЬer requires Arithrnetic<Value_

Nurn> type<Seq>,Nurn>

Nurn

surn(Seq

s,

Nurn

n);

Value

type

у

последовательности

представляет

собой

тип

элементов

в

по­

следовательности.

Ari

thmetic<X,

У>

-

это

концепт,

указывающий,

что

мы

можем

выполнять

арифметические

вычисления

с

типами

Х

и

У.

Это

спа­

сает

нас

от

случайных

попыток

вычисления

sum()

для

vector<string>

или

vector<int*>,

принимая

при

этом

аргументы

vector<int>

и

vector

<complex<douЬle>>. В этом примере нам

понадобился

только

оператор

+=,

но

для

простоты

и

гибкости

мы

не

должны

слишком

строго

ограничивать

наш

шаблонный

аргу-

7.2.

Концепты

(С++20)

139

while (n--) ++р;

11 11

Однонаправленный но не +или+=

итератор

имеет++,

template<Random_access

iterator

Iter>

void

advance(Iter

{

 

 

p+=n;

р,

int

n)

//

Перемещение

р на

п

элементов вперед

11

Итератор с

произвольным

доступом

11

имеет операцию+=

 

 

 

Компилятор

выберет

шаблон

с

наиболее

строгими

требованиями,

кото­

рым

удовлетворяют

аргументы.

list

поддерживает

однонаправленные

ите­

раторы, но не итераторы с произвольным vector, поэтому мы получаем

доступом,

которые поддерживает

void

user(vector<int>: :iterator vip,

{

 

 

 

 

advance(vip,10);

11

Использует

 

advance(lsp,10);

11

Использует

list<string>::iterator lsp)

быструю версию advance ()

медленную версию advance ()

Подобно

другим

перегрузкам,

это

механизм

времени

компиляции,

не вле­

кущий

накладные

расходы

времени

выполнения.

Если

компилятор

не

находит

наилучший

вариант,

он

сообщает

об

ошибке

неоднозначности.

Правила

пере­

грузки

на

основе

концептов

намного

проще,

чем

правила

общей

перегрузки

1.3).

Рассмотрим

сначала

единственный

аргумент

для

нескольких

альтерна­

тивных

функций.

Если аргумент не соответствует концепту, данная

альтернатива не мо­

жет быть выбрана.

 

 

 

Если аргумент соответствует концепту только

в

одной альтернативе, то

выбирается именно эта альтернатива.

 

 

 

Если аргументы двух альтернатив одинаково

хорошо соответствуют

концепту, мы сталкиваемся с неоднозначностью.

 

 

Если аргументы двух альтернатив соответствуют

концепту и один из

них более строгий, чем другой (соответствует

всем

тем же требованиям,

что и другой, и еще некоторым), то выбирается

именно эта альтернатива.

Для

выбранной

альтернативы

должны

выполняться

следующие

условия:

соответствие

всех

аргументов;

при

этом

соответствие всех аргументов как минимум столь же хорошее, как и для других альтернатив; при этом

лучшее

соответствие

как

минимум

одного

аргумента.