Ответ 1
По умолчанию оно auto
. Стандарт [expr.prim.lambda]/4 гласит:
Если лямбда-выражение не содержит лямбда-декларатора, это как если бы лямбда-декларатор был
()
. Тип возврата лямбдаauto
, который заменяется возвращаемым типом возврата, если он указан и/или выводится из операторовreturn
как описано в [dcl.spec.auto].
Мое дополнение.
Таким образом, -> auto
сам по себе не пригодится. Однако мы можем сформировать другие типы возвращаемых данных с auto
, а именно: -> auto&
, -> const auto&
, -> auto&&
, -> decltype(auto)
. Действуют стандартные правила возврата типа возврата. Следует иметь в виду, что auto
никогда не выводится как ссылочный тип, поэтому по умолчанию лямбда возвращает не ссылочный тип.
Несколько (тривиальных) примеров:
// 1.
int foo(int);
int& foo(char);
int x;
auto lambda1 = [](auto& x) { return x; };
static_assert(std::is_same_v<decltype(lambda1(x)), int>);
auto lambda2 = [](auto& x) -> auto& { return x; };
static_assert(std::is_same_v<decltype(lambda2(x)), int&>);
// 2.
auto lambda3 = [](auto x) { return foo(x); };
static_assert(std::is_same_v<decltype(lambda3(1)), int>);
static_assert(std::is_same_v<decltype(lambda3('a')), int>);
auto lambda4 = [](auto x) -> decltype(auto) { return foo(x); };
static_assert(std::is_same_v<decltype(lambda4(1)), int>);
static_assert(std::is_same_v<decltype(lambda4('a')), int&>);
// 3.
auto lambda5 = [](auto&& x) -> auto&& { return std::forward<decltype(x)>(x); };
static_assert(std::is_same_v<decltype(lambda5(x)), int&>);
static_assert(std::is_same_v<decltype(lambda5(foo(1))), int&&>);
static_assert(std::is_same_v<decltype(lambda5(foo('a'))), int&>);
Добавление PiotrNycz. Как указано в комментариях (кредит для @StoryTeller) - реальное использование - это версия с auto&
и const auto&
и "Дегенеративный случай - это просто не то, что нужно отгибать назад, чтобы запретить".
Увидеть:
int p = 7;
auto p_cr = [&]() -> const auto& { return p; };
auto p_r = [&]() -> auto& { return p; };
auto p_v = [&]() { return p; };
const auto& p_cr1 = p_v(); // const ref to copy of p
const auto& p_cr2 = p_cr(); // const ref to p
p_r() = 9; // we change p here
std::cout << p_cr1 << "!=" << p_cr2 << "!\n";
// print 7 != 9 !