Читать «Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14» онлайн - страница 56

Скотт Мейерс

}

Еще более изящный возвращаемый тип auto (см. раздел 1.3) также корректен в С++14:

template<typename E> // С++14

constexpr auto

toUType(E enumerator) noexcept {

 return static_cast<std::underlying_type_t<E>>(enumerator);

}

Независимо от того, как он написан, шаблон toUType позволяет нам обратиться к полю кортежа следующим образом:

auto val = std::get<toUType(UserInfoFields::uiEmail)>(uInfo);

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

Следует запомнить

• Перечисления в стиле С++98 в настоящее время известны как перечисления без областей видимости.

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

• Как перечисления с областями видимости, так и без таковых поддерживают указание базового типа. Базовым типом по умолчанию для перечисления с областью видимости является int. Перечисление без области видимости базового типа по умолчанию не имеет.

• Перечисления с областями видимости могут быть предварительно объявлены. Перечисления без областей видимости могут быть предварительно объявлены, только если их объявление указывает базовый тип.

3.5. Предпочитайте удаленные функции закрытым неопределенным

Если вы предоставляете код другим разработчикам и хотите предотвратить вызов ими некоторой функции, обычно вы просто ее не объявляете. Нет объявления функции — нечего и вызывать. Но иногда С++ объявляет функции вместо вас, и если вы хотите предотвратить вызов таких функций клиентами вашего кода, придется постараться.

Эта ситуация возникает только для “специальных функций-членов”, т.e. функций-членов, которые при необходимости С++ генерирует автоматически. В разделе 3.11 эти функции рассматриваются более подробно, а пока что мы будем беспокоиться только о копирующем конструкторе и копирующем операторе присваивания. Эта глава во многом посвящена распространенным практикам С++98, для которых есть более эффективная замена в С++11, а в С++98, когда вы хотите подавить применение функции-члена, это почти всегда копирующий конструктор, оператор присваивания или они оба.

Подход С++98 для предотвращения применения этих функций состоит в объявлении их как private без предоставления определений. Например, вблизи с основанием иерархии потоков ввода-вывода в стандартной библиотеке С++ находится шаблонный класс basic_ios. Все классы потоков наследуют (возможно, косвенно) этот класс. Копирование потоков ввода-вывода нежелательно, поскольку не совсем очевидно, что же должна делать такая операция. Объект istream, например, представляет поток входных значений, одни из которых могут уже быть считаны, а другие могут потенциально быть считаны позже. Если копировать такой поток, то должно ли это повлечь копирование всех считанных значений, а также значений, которые будут считаны в будущем? Простейший способ разобраться в таких вопросах — объявить их несуществующими. Именно это делает запрет на копирование потоков.