#c #c 11 #auto #lambda
#c #c 11 #авто #лямбда
Вопрос:
#include <vector>
#include <algorithm>
void foo( int )
{
}
int main()
{
std::vector< int > v( { 1,2,3 } );
std::for_each( v.begin(), v.end(), []( auto it ) { foo( it 5 ); } );
}
При компиляции приведенный выше пример запускает вывод ошибки следующим образом :
h4.cpp: In function 'int main()':
h4.cpp:13:47: error: parameter declared 'auto'
h4.cpp: In lambda function:
h4.cpp:13:59: error: 'it' was not declared in this scope
Означает ли это, что ключевое auto
слово не должно использоваться в лямбда-выражениях?
Это работает :
std::for_each( v.begin(), v.end(), []( int it ) { foo( it 5 ); } );
Почему версия с ключевым словом auto не работает?
Комментарии:
1. Я думаю, что даже если это лямбда, он все равно работает как функция и должен иметь подпись. С помощью auto вы позволяете компилятору выбирать тип, поэтому ваш лямбда-код не имеет реальной подписи до времени компиляции.
2. Нам действительно нужны полиморфные лямбды (они же неявные шаблоны) в следующем стандарте. Этот вопрос — лишь один из нескольких случаев, когда люди просто предполагают
auto
, что это работает таким образом. Я не вижу причин, по которым этого не должно быть.3. deft_code , я с тобой. Это логичный вариант использования auto.
Ответ №1:
ключевое слово auto не работает как тип для аргументов функции в C 11. Если вы не хотите использовать фактический тип в лямбда-функциях, вы можете использовать приведенный ниже код.
for_each(begin(v), end(v), [](decltype(*begin(v)) it ){
foo( it 5);
});
Код в вопросе отлично работает на C 14.
Комментарии:
1. Мы собираемся получить
auto
поддержку в лямбда-выражениях в C 14 .2. Обратите внимание на звездочку перед
begin(v)
indecltype
. Вам нужен тип значения, а не тип итератора. (сообщения об ошибках при сбое будут загадочными).
Ответ №2:
C 14 позволяет объявлять параметры лямбда-функции (универсальной лямбда-функции) с помощью функции auto.
auto multiply = [](auto a, auto b) {return a*b;};
Ответ №3:
Это кратко обсуждалось Хербом Саттером во время интервью. Ваше требование auto
аргументов фактически ничем не отличается от требования, чтобы любая функция была объявлена с auto
помощью, например:
auto add(auto a, auto b) -> decltype(a b) { return a b; }
Однако обратите внимание, что на самом деле это вообще не функция, а скорее шаблонная функция, похожая на:
template <typename S, typename T>
auto add(S a, T b) -> decltype(a b) { return a b; }
Таким образом, вы, по сути, запрашиваете средство для превращения любой функции в шаблон путем изменения ее аргументов. Поскольку шаблоны — это совсем другой вид объектов в системе типов C (подумайте обо всех специальных правилах для шаблонов, таких как двухфазный поиск и дедукция), это было бы радикальным изменением дизайна с непредвиденными последствиями, которые, конечно, не будут в стандарте в ближайшее время.
Комментарии:
1. Нет, не спрашиваю и не требую 🙂 Мне просто интересно, почему это не работает.
2. Ну, по сути, это та же причина, что и для «почему не все функции являются шаблонами» — это просто не вписывается в дизайн языка.
Ответ №4:
Тип лямбда-функции должен быть известен до того, как компилятор сможет создать экземпляр std::for_each
. С другой стороны, даже если бы это было теоретически возможно, это auto
можно было бы сделать только после for_each
создания экземпляра, увидев, как вызывается функтор.
Если это вообще возможно, забудьте об for_each
этом и используйте циклы for на основе диапазона, которые намного проще:
for (int it : v) {
foo(it 5);
}
Это также должно хорошо справляться с auto
(и autoamp;
и const autoamp;
) .
for (auto it : v) {
foo(it 5);
}
Комментарии:
1. Да, но это работает только с for_each, а не с другими алгоритмами. например, вы хотите выполнить сортировку по лямбде.