Зачем нужен данный синтаксис, ведь тип результата не вычисляется автоматом?
auto foo(int arg) -> int {}
Этот синтаксис появился в результате включения в стандарт C++ лямбда-выражений.
Лямбда-выражение может быть записано, например, как,
auto foo = [](int arg) -> int { /*...*/ };
Это лямбда-выражение может быть преобразовано в функцию, имеющую тип int( int )
Этот синтаксис переняли для объявления функций. У функции в ее начале должен присутствовать спецификатор(ы) типа возвращаемого выражения. Так как реальный тип возвращаемого значения указывается после списка параметров, то в качестве спецификатора возвращаемого значения в объявлении функции используется спецификатор auto
.
В приведенном вами примере большого смысла так объявлять функцию не имеется. Но иногда тип возвращаемого значения может зависеть от типа вычисления сложного выражения, определить который программисту самостоятельно бывает трудно, да и это может привести к ошибке.
Поэтому этот синтаксис удобен, например, при объявлении шаблонных функций.
Рассмотрите следующую демонстрационную программу.
#include <iostream>
template <class T, class U>
auto foo(const T &x, const U &y) -> decltype( x + y )
{
return x + y;
}
int main()
{
int x = 10;
int y = 20;
std::cout << typeid(foo(x, y)).name() << std::endl;
long z = 30;
std::cout << typeid(foo(x, z)).name() << std::endl;
float f = 40;
std::cout << typeid(foo(x, f)).name() << std::endl;
}
Вывод программы на консоль, например, в MS VC++ может выглядеть как
int
long
float
Заранее сказать, какой будет тип возвращаемого выражения, невозможно. Он зависит от типов параметров функции и от типа вычисляемого выражения. Использование спецификатора типа auto
в данном примере облегчает объявление функции.
Ну, в первую очередь для шаблонов. Компилятор же может не знать возвращаемый тип до того, как увидит аргумент? Например,
template<class T>
??? f(const T& t)
{
return t*5.0;
}
Что тут поставить вместо ???
? А вдруг T - это класс с переопределенным оператором умножения? который возвращает объект другого класса?
А вот так
template<class T>
auto f(const T& t) -> decltype(t*5.0)
{
return t*5.0;
}
никаких проблем...
Он нужен, в частности, для того, чтобы поместить тип возврата в тот контекст, где видны имена параметров функции, соответственно, известна их семантика. Например
auto foo(short a, short b) -> decltype(a + b) { ... }
В данном случае компилятор учтет тот факт, что операнды выражения a + b
будут подвергнуты integral promotions и [на большинстве платформ] дадут результат типа int
. В то же время на платформах, где integral promotions для short
дают unsigned int
тип возврата функции автоматически станет unsigned int
. (Желательна такая "гибкость" или нет - зависит от контекста.)
Также при определении метода класса за пределами определения класса такой тип считается находящимся в области видимости класса, что влияет на процесс поиска неквалифицированных имен
typedef void *Ret;
struct A {
typedef int Ret;
Ret foo();
Ret bar();
};
auto A::foo() -> Ret { return 0; } // OK, `Ret` обозначает именно `A::Ret`
Ret A::bar() { return 0; } // Oшибка - `Ret` обозначает `::Ret`
При использовании "классического" синтаксиса в определении пришлось бы указывать квалифицированное имя типа A::Ret
.
Особенно существенно синтаксис с ->
упрощает запись при определении методов шаблонного класса за пределами класса, ибо квалифицированное имя шаблонного класса может быть очень длинным, да еще и требовать указания ключевого слова typename
.
При использовании этого синтаксиса вы получаете возможность пользоваться "компактной" записью составных типов (аналогично тому, как это делается в using
вместо typedef
)
auto foo() -> int (*)[20] { ... }
В "классической" записи это выглядело бы как
int (*foo())[20] { ... }
что многие сочтут менее удобочитаемым вариантом.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Помогите распарсить эту сроку: интересуют такие параметры на название принтера и дата установки
Дана функция на 200 строк, обрабатывающая большое количество данных, принимающая много параметровПутём неимоверных усилий функция была порезана...