Установка состояния в компоненте Query-apollo

Проблема

C ++ включает полезные общие функции, такие как std::for_each и std::transform, что может быть очень удобно. К сожалению, они также могут быть довольно громоздкими в использовании, особенно если functor , который вы хотите применить, уникален для конкретной функции.

#include 
#include 

namespace {
  struct f {
    void operator()(int) {
      // do something
    }
  };
}

void func(std::vector& v) {
  f f;
  std::for_each(v.begin(), v.end(), f);
}

Если вы используете только f один раз и в этом конкретном месте кажется излишним писать целый класс, просто чтобы сделать что-то тривиальное и одно.

В C ++ 03 у вас может возникнуть соблазн написать что-то вроде следующего, чтобы сохранить functor local:

void func2(std::vector& v) {
  struct {
    void operator()(int) {
       // do something
    }
  } f;
  std::for_each(v.begin(), v.end(), f);
}

однако это недопустимо, f не может быть передано функции template в C ++ 03.

новое решение

C ++ 11 вводит lambdas, чтобы вы могли написать встроенный анонимный функтор для замены struct f. Для небольших простых примеров это может быть более чистым для чтения (он хранит все в одном месте) и потенциально проще поддерживать, например, в простейшей форме:

void func3(std::vector& v) {
  std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}

Лямбда-функции - это просто синтаксический сахар для анонимных функторов .

Типы возвращаемых данных

В простых случаях для вас выводится тип возврата лямбда, например:

void func4(std::vector& v) {
  std::transform(v.begin(), v.end(), v.begin(),
                 [](double d) { return d < 0.00001 ? 0 : d; }
                 );
}

, однако, когда вы начинаете писать больше сложный lambdas, вы быстро столкнетесь с случаями, когда тип возврата не может быть выведен компилятором, например:

void func4(std::vector& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

Чтобы разрешить это, вам разрешено явно указывать тип возврата для лямбда-функции, используя -> T:

void func4(std::vector& v) {
    std::transform(v.begin(), v.end(), v.begin(),
        [](double d) -> double {
            if (d < 0.0001) {
                return 0;
            } else {
                return d;
            }
        });
}

«Захват» переменных

До сих пор мы не использовали ничего, кроме того, что было передано лямбда внутри него, но мы также можем использовать другие переменные, в пределах лямбда. Если вы хотите получить доступ к другим переменным, вы можете использовать предложение capture ([] выражения), которое до сих пор не использовалось в этих примерах, например:

void func5(std::vector& v, const double& epsilon) {
    std::transform(v.begin(), v.end(), v.begin(),
        [epsilon](double d) -> double {
            if (d < epsilon) {
                return 0;
            } else {
                return d;
            }
        });
}

Вы можете выполнять захват обоими ссылку и значение, которые вы можете указать с помощью & и = соответственно:

  • [&epsilon] захват по ссылке
  • [&] захватывает все переменные, используемые в lambda по ссылке
  • [=] фиксирует все переменные, используемые в лямбда по значению
  • [&, epsilon] захватывает переменные, такие как [& amp;], но epsilon по значению
  • [=, &epsilon] захватывает переменные, такие как [=], но epsilon по ссылке

Порожденный operator() по умолчанию const, с импликацией, которая захватывает, будет const когда вы обращаетесь к ним по умолчанию. Это приводит к тому, что каждый вызов с одним и тем же входом даст тот же результат, однако вы можете пометить лямбда как mutable , чтобы запросить, что созданный operator() не const.

16
задан The Kaizer 20 May 2018 в 16:33
поделиться