Не ошибается ли моя книжная дискуссия о типах возврата лямбда?
В моей книге сказано:
Lambdas с телами функций, которые содержат что-либо, кроме одного оператора return, который не указывает возвращаемый тип return return.
но это:
auto f = []{
int i=0; i++;
return std::string("foo");
};
std::cout << f() << std::endl;
фактически компилирует и выводит "foo", но этот lambda expr имеет больше, чем просто один оператор return, поэтому он должен возвращать void, потому что он не указывает вручную "- > std::string" в качестве возвращаемого типа.
Что здесь происходит?
Я использую компилятор Apple в последнем Xcode 4.6, основанный на Clang 3.2, кажется:
clang --version
Apple LLVM версия 4.2 (clang-425.0.24) (на основе LLVM 3.2svn)
Цель: x86_64-apple-darwin12.2.0
Модель темы: posix
Ответы
Ответ 1
Книга точно отражает правила в проекте n3290 Стандарта. Возможно, ваш компилятор реализовал другой проект.
В разделе 5.1.2p4 проект гласит
Если лямбда-выражение не включает тип возвращаемого типа возврата, это как будто тип trailing-return-type обозначает следующий тип:
- если составной оператор имеет вид
{
выражение-specifier-seq optreturn
выражение ;
}
тип возвращаемого выражения после преобразования lvalue-to-rval, преобразования матрицы в указатель и преобразования функции в указатель; - в противном случае void.
Синтаксическая конструкция attribute-specifier-seq может быть alignas
или атрибутами с двойной привязкой. Непеременные объявления.
Проект n3485, который после публикации С++ 11 (т.е. работает в направлении С++ 1y), содержит ту же формулировку. Я не знаю, было ли другое правило в каком-то проекте раньше, чем n3290.
Ответ 2
Если вы используете популярные компиляторы (gcc, Visual Studio), вам обычно не нужно указывать тип возвращаемого значения, если компилятор может определить его однозначно - как в вашем примере.
В следующем примере показана lambda, для которой требуется явная информация о возвращаемом типе:
auto lambda = [](bool b) -> float
{
if (b)
return 5.0f;
else
return 6.0;
};
Я спросил Бьярна Страуструпа по этому поводу, его комментарий:
I do not know if C++11 allows the deduction of the return type is there are several return statements with identical return type. If not, that's planned for C++14.
Ответ 3
Я не уверен, что делать из цитаты в вопросе, но вот что говорит о стандарте С++ 11 о lambdas без декларатора или типа возвращаемого значения:
Если лямбда-выражение не содержит лямбда-декларатора, оно равно если лямбда-декларатор был(). Если лямбда-выражение не включают тип trailing-return-type, это похоже на тип возвращаемого типа возврата обозначает следующий тип (5.1.2p4):
- если составной оператор имеет вид {expression-specifier-seqopt return expression; } тип возвращаемое выражение после преобразования lvalue-to-rvalue (4.1), преобразование массива в указатель (4.2) и преобразование функции в указатель (4.3);
- в противном случае void.
Ответ 4
Clang реализует предлагаемое решение С++ core issue 975. Это позволяет произвольному телу для лямбда с любым числом операторов return и выводит возвращаемое значение из возвращаемого выражения при условии, что все они должны производить один и тот же тип.
В С++ 14 эта поддержка далее обобщается N3638, которая была проголосована за рабочий проект стандарта на Бристольское совещание РГ21.
Ответ 5
Черновик n3485 указывает, что если компилятор может однозначно определить тип возвращаемого значения, это позволит лямбда не указывать его.