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

Шрифт
Интервал

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

>template // Работает, но

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

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

>{

> authenticateUser();

> return c[i];

>}

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

При таком объявлении >authAndAccess возвращает тот тип, который возвращает >operator[] при применении к переданному контейнеру, в точности как мы и хотели.

С++11 разрешает вывод возвращаемых типов лямбда-выражений из одной инструкции, а С++14 расширяет эту возможность на все лямбда-выражения и все функции, включая состоящие из множества инструкций. В случае >authAndAccess это означает, что в С++ 14 мы можем опустить завершающий возвращаемый тип, оставляя только одно ведущее ключевое слово >auto. При таком объявлении >auto означает, что имеет место вывод типа. В частности, это означает, что компиляторы будут выводить возвращаемый тип функции из ее реализации:

>template // С++14;

>auto authAndAccess(Container& с, Index i)    // Не совсем

>{                                            // корректно

> authenticateUser();

> return c[i];       // возвращаемый тип выводится из c[i]

>}

В разделе 1.2 поясняется, что для функций с >auto-спецификацией возвращаемого типа компиляторы применяют вывод типа шаблона. В данном случае это оказывается проблематичным. Как уже говорилось, >operator[] для большинства контейнеров с объектами типа возвращает >Т&, но в разделе 1.1 поясняется, что в процессе вывода типа шаблона “ссылочность” инициализирующего выражения игнорируется. Рассмотрим, что это означает для следующего клиентского кода:

>std::deque d;

>…

>authAndAccess(d, 5) = 10; // Аутентифицирует пользователя, воз-

>                          // вращает d[5], затем присваивает ему

>                          // значение 10. Код не компилируется!

Здесь >d[5] возвращает >int&, но вывод возвращаемого типа >auto для >authAndAccess отбрасывает ссылку, тем самым давая возвращаемый тип >int. Этот >int, будучи возвращаемым значением функции, является >rvalue, так что приведенный выше код пытается присвоить этому >rvalue типа int значение 10. Это запрещено в С++, так что данный код не компилируется.

Чтобы заставить >authAndAccess работать так, как мы хотим, нам надо использовать для ее возвращаемого типа вывод типа >decltype, т.е. указать, что >authAndAccess должна возвращать в точности тот же тип, что и выражение >с[i]. Защитники С++, предвидя необходимость использования в некоторых случаях правил вывода типа >decltype, сделали это возможным в С++14 с помощью спецификатора >decltype(auto). То, что изначально может показаться противоречием (>decltypeи>auto?), в действительности имеет смысл: >auto указывает, что тип должен быть выведен, а >decltype говорит о том, что в процессе вывода следует использовать правила >decltype. Итак, можно записать >authAndAccess следующим образом:

>template // С++14; работает,

>decltype(auto)                               // но все еще

>authAndAccess(Containers с, Index i)         // требует

>{                                            // уточнения

> authenticateUser();

> return c[i];

>}

Теперь >authAndAccess действительно возвращает то же, что и >c[i]. В частности, в распространенном случае, когда >c[i] возвращает >Т&, >authAndAccess также возвращает >Т&, и в том редком случае, когда >c[i] возвращает объект, >authAndAccess также возвращает объект.

Использование >decltype(auto) не ограничивается возвращаемыми типами функций. Это также может быть удобно для объявления переменных, когда вы хотите применять правила вывода типа >decltype к инициализирующему выражению:

>Widget w;

>const Widget& cw = w;


>auto myWidget1 = cw;           // Вывод типа auto:


>                               // тип myWidget1 - Widget

>decltype(auto) myWidget2 = cw; // Вывод типа decltype:

>                               // тип myWidget2 - const Widget&

Я знаю, что вас беспокоят два момента. Один из них — упомянутое выше, но пока не описанное уточнение >authAndAccess. Давайте, наконец-то, разберемся в этом вопросе. Еще раз посмотрим на версию >authAndAccess в С++14:

>template

>decltype(auto) authAndAccess(Container& с, Index i);

Контейнер передается как lvalue-ссылка на неконстантный объект, поскольку возвращаемая ссылка на элемент контейнера позволяет клиенту модифицировать этот контейнер. Но это означает, что этой функции невозможно передавать контейнеры, являющиеся rvalue. rvalue невозможно связать с lvalue-ссылками (если только они не являются lvalue-ссылками на константные объекты, что в данном случае очевидным образом не выполняется).


Еще от автора Скотт Мейерс
Эффективное использование STL

В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.


Как функции, не являющиеся методами, улучшают инкапсуляцию

Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Виртуальная библиотека Delphi

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


Обработка баз данных на Visual Basic.NET

Это практическое руководство разработчика программного обеспечения на Visual Basic .NET и ADO.NET, предназначенное для создания приложений баз данных на основе WinForms, Web-форм и Web-служб. В книге описываются практические способы решения задач доступа к данным, с которыми сталкиваются разработчики на Visual Basic .NET в своей повседневной деятельности. Книга начинается с основных сведений о создании баз данных, использовании языка структурированных запросов SQL и системы управления базами данных Microsoft SQL Server 2000.


Исчерпывающее руководство по написанию всплывающих подсказок

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


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

Embedded system software. General requirements for development and documentationСтандарт подготовлен в развитие ГОСТ Р ИСО/МЭК 12207-99 «Информационная технология. Процессы жизненного цикла программных средств» с целью учета специфики разработки и документирования программного обеспечения встроенных систем реального времени.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.