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

Скотт Мейерс

1.3. Знакомство с decltype

decltype — создание странное. Для данного имени или выражения decltype сообщает вам тип этого имени или выражения. Обычно то, что сообщает decltype, — это именно то, что вы предсказываете. Однако иногда он дает результаты, которые заставляют вас чесать в затылке и обращаться к справочникам или сайтам.

Мы начнем с типичных случаев, в которых нет никаких подводных камней. В отличие от того, что происходит в процессе вывода типов для шаблонов и auto (см. разделы 1.1 и 1.2), decltype обычно попугайничает, возвращая точный тип имени или выражения, которое вы передаете ему:

const int i = 0;         // decltype(i) - const int

bool f(const Widget& w); // decltype(w) - const Widget&

                         // decltype(f) - bool(const Widget&)

struct Point {

 int x, y;               // decltype (Point::x) - int

};                       // decltype(Point::y) – int

Widget w;                // decltype(w) – Widget

if (f(w)) …              // decltype (f(w)) — bool

template<typename Т>     // Упрощенная версия std::vector

class vector {

public:

 …

 T& operator[](std::size_t index);

};

vector<int> v;           // decltype(v) – vector<int>

if (v[0] == 0) …                  // decltype(v[0]) - int&

Видите? Никаких сюрпризов.

Пожалуй, основное применение decltype в С++11 — объявление шаблонов функций, в которых возвращаемый тип функции зависит от типов ее параметров. Предположим, например, что мы хотим написать функцию, получающую контейнер, который поддерживает индексацию с помощью квадратных скобок (т.е. с использованием “[]”) с индексом, а затем аутентифицирует пользователя перед тем как вернуть результат операции индексации. Возвращаемый тип функции должен быть тем же, что и тип, возвращаемый операцией индексации.

operator[] для контейнера объектов типа Т обычно возвращает Т&. Например, это так в случае std::deque и почти всегда — в случае std::vector. Однако для std::vector<bool> оператор operator[] не возвращает bool&. Вместо этого он возвращает новый объект. Все “почему” и “как” данной ситуации рассматриваются в разделе 2.2, но главное здесь то, что возвращаемый оператором operator[] контейнера тип зависит от самого контейнера.

decltype упрощает выражение этой зависимости. Вот пример, показывающий применение decltype для вычисления возвращаемого типа. Этот шаблон требует уточнения, но пока что мы его отложим.

template<typename Container, typename Index> // Работает, но

auto authAndAccess(Container& с, Index i)    // требует

 ->decltype(c[i])                            // уточнения

{

 authenticateUser();

 return c[i];

}

Использование auto перед именем функции не имеет ничего общего с выводом типа. На самом деле оно указывает, что использован синтаксис С++11 — завершающий возвращаемый тип (trailing return type), т.е. что возвращаемый тип функции будет объявлен после списка параметров (после “->”). Завершающий возвращаемый тип обладает тем преимуществом, что в спецификации возвращаемого типа могут использоваться параметры функции. В authAndAccess, например, мы указываем возвращаемый тип с использованием с и i. Если бы возвращаемый тип, как обычно, предшествовал имени функции, c и i были бы в нем недоступны, поскольку в этот момент они еще не были объявлены.