Использование auto в лямбда-функции

#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) in decltype . Вам нужен тип значения, а не тип итератора. (сообщения об ошибках при сбое будут загадочными).

Ответ №2:

C 14 позволяет объявлять параметры лямбда-функции (универсальной лямбда-функции) с помощью функции auto.

 auto multiply = [](auto a, auto b) {return a*b;};
  

Подробнее: http://en.cppreference.com/w/cpp/language/lambda

Ответ №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, а не с другими алгоритмами. например, вы хотите выполнить сортировку по лямбде.