Объекты, допускающие только перемещение, можно передавать функциям в качестве параметров и возвращать из функций, но если вы захотите переместить содержимое l-значения, то должны будете выразить свое намерение явно, воспользовавшись функцией std::move() или оператором static_cast.

Спецификатор = delete можно задать для любой функции, а не только для копирующего конструктора и оператора присваивания. Тем самым вы ясно даете понять, что функция отсутствует. Но это еще не все — удаленная функция участвует в разрешении перегрузки, как любая другая, и вызывает ошибку компиляции, только если будет выбрана. Этим можно воспользоваться для исключения некоторых перегруженных вариантов. Например, если функция принимает параметр типа short, то сужение типа int можно предотвратить, написав перегруженный вариант, который принимает int, и объявив его удаленным:

void foo(short);

void foo(int) = delete;

Любую попытку вызвать foo с параметром типа int компилятор встретит в штыки, так что вызывающей программе придётся явно привести параметр к типу short:

foo(42); ←Ошибка, перегрузка для int удалена

foo((short)42); ←Правильно

<p>А.3. Умалчиваемые функции</p>

Если механизм удаленных функций позволяет явно объявить, что функция не реализована, то назначение умалчиваемых (defaulted) функций прямо противоположное - это средство указать, что компилятор должен автоматически сгенерировать реализацию функции «по умолчанию». Разумеется, это можно делать только для функций, которые компилятор и так генерирует: конструкторов, деструкторов, копирующих и перемещающих конструкторов, копирующих и перемещающих операторов присваивания.

Зачем это может понадобиться? Есть несколько причин.

• Чтобы изменить видимость функции. По умолчанию генерируемые компилятором функции открыты. Если требуется, чтобы они были защищенными или даже закрытыми, то писать их придётся самостоятельно. Но объявив функцию умалчиваемой, вы можете заставить компилятор сгенерировать ее и одновременно изменить уровень доступа.

• Для документирования. Если сгенерированной компилятором версии достаточно, то имеет смысл так прямо и сказать. Тогда всякий, кто впоследствии будет читать код, поймёт, что это сделано намеренно.

• Чтобы заставить компилятор сгенерировать функцию, которую в противном случае он не стал бы генерировать. Обычно это касается конструкторов по умолчанию, которые автоматически генерируются, только если нет ни одного определенного пользователем конструктора. Если вы хотите, например, определить свой копирующий конструктор, то, объявив конструктор по умолчанию умалчиваемым, заставите компилятор сгенерировать его.

• Чтобы сделать деструктор виртуальным и при этом генерируемым компилятором.

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

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

Умалчиваемые функции объявляются путем добавления спецификатора = default, например:

class Y {

private:

 Y() = default; ←Изменяем видимость

public:

 Y(Y&) = default; ←Принимаем не-const ссылку

 T& operator=(const Y&) = default;←┐объявляем умалчиваемой

                                   │для документирования

protected:

 virtual ~Y() = default; ←Изменяем видимость и добавляем virtual

};

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

• Объекты с тривиальными копирующим конструктором, копирующим оператором присваивания и деструктором можно копировать с помощью memcpy или memmove.

• Литеральные типы, используемые в constexpr-функциях (см. раздел А.4) обязаны обладать тривиальными конструктором, копирующим конструктором и деструктором.

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

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