Урок №62. Вывод типов: ключевое слово auto

  Юрий  | 

  |

  Обновл. 13 Сен 2021  | 

 112627

 ǀ   8 

На этом уроке мы рассмотрим вывод типов с помощью ключевого слова auto в языке С++.

Вывод типов в C++11

До C++11 ключевое слово auto было наименее используемым ключевым словом в языке C++. Из урока №48 мы уже знаем, что локальные переменные имеют автоматическую продолжительность жизни (создаются в точке определения и уничтожаются в конце блока, в котором определены).

Ключевое слово auto использовалось для явного указания, что переменная должна иметь автоматическую продолжительность жизни:

Однако, поскольку все переменные в новых версиях языка C++ по умолчанию имеют автоматическую продолжительность жизни (если явно не указать другой тип продолжительности жизни), ключевое слово auto стало лишним и, следовательно, устаревшим.

В C++11 значение ключевого слова auto изменилось. Рассмотрим следующий стейтмент:

Если C++ и так знает, что 4.0 является литералом типа double, то зачем нам дополнительно указывать, что переменная x должна быть типа double? Правда, было бы неплохо, если бы мы могли указать переменной принять соответствующий тип данных, основываясь на инициализируемом значении?

Начиная с C++11 ключевое слово auto при инициализации переменной может использоваться вместо типа переменной, чтобы сообщить компилятору, что он должен присвоить тип переменной исходя из инициализируемого значения. Это называется выводом типа (или «автоматическим определением типа данных компилятором»). Например:

Это работает даже с возвращаемыми значениями функций:

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

Используя ключевое слово auto вместо фундаментальных типов данных, мы не сэкономим много времени или усилий, но на следующих уроках, когда типы данных будут более сложными и длинными, ключевое слово auto может очень пригодиться.

Ключевое слово auto и параметры функций


Многие новички пытаются сделать что-то вроде следующего:

Это не сработает, так как компилятор не может определить типы данных для параметров функции a и b во время компиляции.

Если вы хотите создать функцию, которая будет работать с разными типами данных, то вам лучше воспользоваться шаблонами функций, а не выводом типа. Это ограничение, возможно, отменят в будущих версиях C++ (когда auto будет использоваться как сокращенный способ создания шаблонов функций), но в C++14 это не работает. Единственное исключение — лямбда-выражения (но это уже другая тема).

Вывод типов в C++14

В C++14 функционал ключевого слова auto был расширен до автоматического определения типа возвращаемого значения функции. Например:

Так как выражение a − b является типа int, то компилятор делает вывод, что и функция должна быть типа int.

Хотя это может показаться удобным, так делать не рекомендуется. Тип возвращаемого значения функции помогает понять caller-у, что именно функция должна возвращать. Если конкретный тип не указан, то caller может неверно интерпретировать тип возвращаемого значения, что может привести к непреднамеренным ошибкам.

Так почему же использование auto при инициализации переменных — это хорошо, а с функциями — плохо? Дело в том, что auto можно использовать при определении переменной, так как значение, из которого компилятор делает выводы о типе переменной, находится прямо там — в правой части стейтмента. Однако с функциями это не так — нет контекста, который бы указывал, какого типа данных будет возвращаемое значение. Фактически, пользователю придется лезть в тело функции, чтобы определить тип возвращаемого значения. Следовательно, такой способ не только не практичен, но и более подвержен ошибкам.

trailing-синтаксис в C++11


В C++11 появилась возможность использовать синтаксис типа возвращаемого значения trailing (или просто «trailing-синтаксис»), когда компилятор делает выводы о типе возвращаемого значения по конечной части прототипа функции. Например, рассмотрим следующее объявление функции:

В C++11 это можно записать как:

В этом случае auto не выполняет вывод типа — это всего лишь часть синтаксиса типа возвращаемого значения trailing. Зачем это стоит использовать? В основном, из-за удобства. Например, можно выстроить в колонку все названия ваших функций:

Но этот синтаксис более полезен в сочетании с некоторыми другими продвинутыми особенностями языка C++ такими, как классы и ключевое слово decltype.

На данный момент я рекомендую придерживаться традиционного (обычного) синтаксиса для определения типа возвращаемого значения функции (без использования ключевого слова auto).

Заключение

Начиная с C++11 ключевое слово auto может использоваться вместо типа переменной при инициализации для выполнения вывода типа. Во всех других случаях использования ключевого слова auto следует избегать, если на это нет веских причин.


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (448 оценок, среднее: 4,92 из 5)
Загрузка...

Комментариев: 8

  1. anonymous:

    Таки в -std=c++20 можно параметры делать auto

  2. Антонида:

    Большое спасибо за труд! Очень информативные, понятные и полезные статьи! В статье вы пишете: "Мы поговорим детально о других использованиях auto, когда будем рассматривать ключевое слово decltype." Можно, пожалуйста, ссылочку на статью, где это обсуждается?

    1. Фото аватара Юрий:

      На этих уроках действительно не рассматривается использование decltype. Могу посоветовать эту статью — https://habr.com/ru/post/206458/, либо это объяснение — https://en.cppreference.com/w/cpp/language/decltype.

  3. Артемий:

    Спасибо за очередной урок

    1. Фото аватара Юрий:

      Пожалуйста)

  4. Torgu:

    за овер 60 уроков у меня сложилось несколько вопросу по плавающей точке:
    1. Почему вы все время используете double? Ведь точности того же float будет достаточно для большинства дробей
    2. В начале этого урока пишется, что "4.0" — литерал типа double. Почему double? Разве стандартный не float?
    3. В уроке о плавающей точке при инициализации переменной типа float вы добавляли f сразу после значения. Зачем? Ведь тип уже указан — float, зачем еще дополнительно что-то писать? Думал позже пойму, но нет, вот уже какой десяток уроков, до сих пор не догоняю

    1. Torgu:

      UPD: в итоге, сам ответил на свои вопросы 😉 Оказывается double стандартный тип для плавающей точки, а мне почему-то упорно казалось, что float. А фичу с постфиксом 'f' для чисел так и не понял

      1. Владимир:

        Добавление к константе постфикса f или F для float используется для повышения оптимизации, поскольку компилятор видит суффикс f и понимает, что это константа типа float, а не double. следовательно, не выполняется преобразование из double в float. А то, что тип double используется по умолчанию, говорилось ещё в уроке про литералы и магические числа (36 урок).

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *