Std:: bind и std:: функции

int func(int x){return x;}
...
std::function<int(int)> x = std::bind(func, std::placeholders::_1);
x(123);
  • Действительно ли x(123) вызывает operator() функтора, сгенерированного std::function, который в свою очередь вызывает operator() функтора, который std::bind генерирует, который в конечном итоге вызывает func? Оптимизируется ли это в чем-то оптимальном, чем вызов func(123)?
  • Где живет функтор, который std::bind генерирует? В каком объеме? И как std::bind назовите его? (возможны конфликты имен)
  • Может ли lambdas заменить все использования std::bind?
  • Является ли std::bind оптимальным, чем реализация вместо lambda?
  • Что связано с синтаксисом аргумента шаблона std::function? Как это анализируется и как я могу использовать синтаксис аргумента шаблона в другом месте?

Ответ 1

Действительно ли x (123) вызывает оператор() функтора, который генерирует std:: function, который, в свою очередь, вызывает оператор() функтора, который std:: bind генерирует, который в конечном итоге вызывает func? Оптимизируется ли это в чем-то оптимальном, чем вызов функции func (123)?

Я бы не описал operator() of std::function как "сгенерированный" (это обычный член), но в остальном это хорошее описание. Оптимизация зависит от вашего компилятора, но следует предупредить, что для оптимизации косвенности std::function (которая требует использования стирания типа) компилятору, возможно, потребуется выполнить героизм.

Где живет функтор, который генерирует std:: bind? В каком объеме? И как std:: bind name it? (возможны конфликты имен)

Вызов std::bind возвращает функтор неуказанного типа, и копия этого функтора сохраняется внутри объекта x. Эта копия будет жить до тех пор, пока x. Нет никакого имени, поэтому я не уверен, что вы подразумеваете под этим.

Может ли lambdas заменить все виды использования std:: bind?

Нет. Рассмотрим auto bound = std::bind(functor, _1);, где functor - тип с перегруженным operator(), скажем, на long и int. Тогда bound(0L) не имеет такого же эффекта, как bound(0), и вы не можете реплицировать его с помощью лямбда.

Является ли std:: bind оптимальным, если вместо него использовать лямбда?

Это зависит от компилятора. Измерьте себя.

Что связано с синтаксисом аргумента шаблона std:: function? Как это анализируется и как я могу использовать синтаксис аргумента шаблона в другом месте?

Это тип функции. Возможно, вы уже знакомы с синтаксисом указателей/ссылок на функции: void(*)(), int(&)(double). Затем просто удалите указатель/ссылку из типа, и у вас есть только тип функции: void(), int(double). Вы можете использовать их так:

typedef int* function_type(long);
function_type* p; // pointer to function

Ответ 2

1. На самом деле x(123) вызывает operator() функтора, сгенерированного std::function, который в свою очередь вызывает operator() функтора, который std::bind генерирует, который в конечном итоге называет func? Оптимизируется ли это в чем-то оптимальном, чем вызов func(123)?

Если у вас включена оптимизация, "материал" встраивается, и вы можете рассчитывать на то, что это будет оптимальным, как вызов func(123).

2. Где живет функтор, который std::bind генерирует? В каком объеме? И как std::bind назовите его? (возможны конфликты имен)

Точный: bind генерирует "мимолетное", определенное для реализации выражение bind, которое присваивается function<>. Функция - это просто шаблон класса (спасибо, Люк Т.). И он живет в стандартной библиотеке. Однако выражения привязки определяются реализацией.

В стандартную библиотеку входят черты (std::is_bind_expression<>), чтобы разрешить обнаружение MPL таких выражений. Одной из решающих особенностей выражений связывания над std:: function является то, что они (я бы назвал) отложенными вызываемыми объектами (т.е. Они сохраняют полную семантику сайта вызова, включая возможность выбора перегрузок на фактическом сайте приложения). std::function<>, с другой стороны, фиксирует один прототип и внутренне сохраняет вызываемый объект по типу стирания (думаю variant или any).

3. Может ли lambdas заменить все использования std:: bind?

4. Является ли std:: bind оптимальным, если вместо него использовать lambda?

AFAICT lambdas должен скомпилироваться примерно так же, как и выражения привязки. Одна вещь, о которой я думаю, что lambdas не может сделать, что выражения связи могут быть nested bind expressions Изменить. Хотя конкретная идиома вложенных выражений связывания не реплицируется с помощью lambdas, lambdas, конечно, могут выразить (почти) то же самое более естественно:

 bind(f, bind(g, _1))(x); 
 // vs.
 [](int x) { f(g(x)); };

 

5. Что связано с синтаксисом аргумента шаблона std::function? Как это анализируется и как я могу использовать синтаксис аргумента шаблона в другом месте?

Это просто сигнатура функции (тип функции), передаваемая в качестве параметра шаблона.

Вы также можете использовать его как тип параметра функции, который деградирует до указателя функции (подобно тому, как параметры по умолчанию массива ухудшаются до указателей, спасибо Дэвиду!). На практике большинство в любом месте, если вам не нужно указывать переменную/тип:

 void receiveFunction(void(int, double)); // spunky 'function<>'-style syntax

 void sample(int, double) { } 

 int main()
 { 
     receiveFunction(sample);
 }

 void receiveFunction(void (*f)(int, double)) // boring 'old' style syntax
 //                   void ( f)(int, double)  // ... also ok
 {
     // ..
 }

Ответ 3

Может ли lambdas заменить все виды использования std:: bind?

С++ 14 позволит lambdas в основном заменить bind. Отвечая, в частности, на ответа Люка Дантона, в С++ 14 вы можете писать шаблонные lambdas с использованием auto, так что bound(0) и bound(0L) ведут себя по-другому.