2011-11-10 2 views
11
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? Как это анализируется и как я могу использовать синтаксис аргумента шаблона в другом месте?
+2

Для 2. вас может заинтересовать http://www.artima.com/cppsource/type_erasure.html – Flexo

+4

Один вопрос за один раз, пожалуйста. Каждый вопрос о СО является вопросом. –

+0

Это скорее набор вопросов, чем конкретный вопрос, и они варьируются от синтаксиса (для аргумента функции <> ') до поведения (где результат live live? Может заменить лямбда?) Производительность (будет он оптимизирован?) –

ответ

16

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

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

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

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

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

No. Рассмотрим 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 для единственного правильного ответа на вопрос №2: функтор просто объект, магического класса не участвует. –

+1

Пригвожденный статический полиморфизм (привязка) к мономорическим прототипам (функция <>) разницы в первый раз. :) Совершенно глубокая, но легко забываемая разница. (У вас был мой +1 с самого начала) – sehe

+0

+1 для варианта использования 'bind', который не может быть реплицирован лямбдой. –

6

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

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

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

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

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

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

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

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

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

Предполагая, что 'f' и' g' не перегружены, то выражение вложенного связывания может быть выражено как lambda: '[] (T t) {return f (g (t)); } '. –

+0

@LucDanton: нашел информацию в вашем ответе. +1 для этого – sehe

+1

Я не согласен с точкой 2: правильный ответ заключается в том, что функтор «сгенерирован» с помощью 'bind' отсутствует, просто временный объект, возвращаемый функцией, который не имеет имени и будет жить в течение времени выражения он появляется (как и все временные). Это временное значение используется для инициализации 'x'. –

0

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

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

Смежные вопросы