Читать «Эффективный и современный С++. 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 — ->
”). Завершающий возвращаемый тип обладает тем преимуществом, что в спецификации возвращаемого типа могут использоваться параметры функции. В authAndAccess
, например, мы указываем возвращаемый тип с использованием с
и i
. Если бы возвращаемый тип, как обычно, предшествовал имени функции, c
и i
были бы в нем недоступны, поскольку в этот момент они еще не были объявлены.