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

Ответы [ 3 ]

16 голосов
/ 10 ноября 2011

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

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

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

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

Могут ли лямбды заменить все виды использования 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
6 голосов
/ 10 ноября 2011

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

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

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

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

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

3. Могут ли лямбды заменить все виды использования std :: bind?

4. Является ли std :: bind asоптимально, если вместо этого реализовать его как лямбду?

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

 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
 {
     // ..
 }
0 голосов
/ 12 сентября 2014

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...