Использование и синтаксис std::function

Мне необходимо использовать std::function, но я не знаю, что означает следующий синтаксис.

std::function<void()> f_name = []() { FNAME(); };

Какова цель использования std::function? Это сделать указатель на функцию?

Ответы

Ответ 1

std::function является объектом стирания типа. Это означает, что он стирает детали того, как происходят некоторые операции, и предоставляет им единый интерфейс времени выполнения. Для std::function основными операциями 1 являются копирование/перемещение, уничтожение и "вызов" с помощью operator() - "оператор вызова как функция".

В менее заумном английском это означает, что std::function может содержать практически любой объект, который действует как указатель на функцию в том, как вы его вызываете.

Поддерживаемая подпись идет внутри angular скобок: std::function<void()> принимает нулевые аргументы и ничего не возвращает. std::function< double( int, int ) > принимает два аргумента int и возвращает double. В общем, std::function поддерживает сохранение любого функционально-подобного объекта, аргументы которого могут быть преобразованы, из его списка аргументов, а возвращаемое значение может быть преобразовано в его возвращаемое значение.

Важно знать, что std::function и лямбды разные, если совместимы, звери.

Следующая часть строки - лямбда. Это новый синтаксис в С++ 11, добавляющий возможность писать простые функциональные объекты - объекты, которые можно вызывать с помощью (). Такие объекты можно стирать по типу и хранить в std::function за счет некоторых накладных расходов времени выполнения.

[](){ code } в частности это действительно простая лямбда. Это соответствует этому:

struct some_anonymous_type {
  some_anonymous_type() {}
  void operator()const{
    code
  }
};

экземпляр вышеуказанного простого типа псевдо-функции. Фактический класс, подобный описанному выше, "изобретен" компилятором с уникальным именем, определяемым реализацией (часто включая символы, которые не может содержать ни один пользовательский тип) (я не знаю, возможно ли, что вы можете следовать стандарту, не изобретая такой класс, но каждый компилятор, которого я знаю, на самом деле создает класс).

Полный лямбда-синтаксис выглядит следующим образом:

[ capture_list ]( argument_list )
-> return_type optional_mutable
{
  code
}

но многие части можно опустить или оставить пустыми. Перехват захвата соответствует как конструктору результирующего анонимного типа, так и его переменным-членам, аргумент аргумента аргумента operator() и тип возвращаемого значения возвращаемого типа. Конструктор лямбда-экземпляра также вызывается волшебным образом, когда экземпляр создается с помощью capture_list.

[ capture_list ]( argument_list ) -> return_type { code }

в основном становится

struct some_anonymous_type {
  // capture_list turned into member variables
  some_anonymous_type( /* capture_list turned into arguments */ ):
    /* member variables initialized */
  {}
  return_type operator()( argument_list ) const {
    code
  }
};

1 Кроме того, RTTI сохраняется (typeid) и включена операция приведения типа к исходному типу.

Ответ 2

Позвольте разбить линию на части:

станд :: функция

Это объявление для функции, не принимающей никаких параметров, и не возвращающей значения. Если функция вернула int, она будет выглядеть так:

std::function<int()>

Аналогично, если бы он принял параметр int:

std::function<int(int)>

Я подозреваю, что ваша основная путаница - это следующая часть.

[]() { FNAME(); };

Часть [] называется объявлением. Здесь вы помещаете переменные, которые являются локальными для объявления вашей лямбда, и что вы хотите быть доступными в самой лямбда-функции. Это говорит: "Я не хочу, чтобы что-то было захвачено". Если это было в определении класса и вы хотели, чтобы класс был доступен для лямбда, вы можете сделать следующее:

[this]() { FNAME(); };

Следующая часть - это параметры, передаваемые лямбда, точно так же, как если бы это была регулярная функция. Как упоминалось ранее, std::function<void()> является сигнатурой, указывающей на метод, который не принимает никаких параметров, поэтому он также пуст.

Остальная часть этого тела является телом самой лямбды, как если бы это была обычная функция, которую мы можем видеть, просто вызывает функцию FNAME.

Другой пример

Скажем, у вас есть следующая подпись, то есть для чего-то, что может суммировать два числа.

std::function<int(int, int)> sumFunc;

Теперь мы можем объявить лямбду так:

sumFunc = [](int a, int b) { return a + b; };

Не уверен, что вы используете MSVC, но здесь ссылка в синтаксисе выражения lamda:

http://msdn.microsoft.com/en-us/library/dd293603.aspx