В чем разница между std:: function < > и стандартным указателем функции?
то есть:
typedef std::function<int(int)> FUNCTION;
typedef int (*fn)(int);
Действительно ли они одинаковы?
В чем разница между std:: function < > и стандартным указателем функции?
то есть:
typedef std::function<int(int)> FUNCTION;
typedef int (*fn)(int);
Действительно ли они одинаковы?
Указатель функции - это адрес фактической функции, определенной в С++. std::function
- это оболочка, которая может содержать любой тип вызываемого объекта (объекты, которые могут использоваться как функции).
struct FooFunctor
{
void operator()(int i) {
std::cout << i;
}
};
// Since `FooFunctor` defines `operator()`, it can be used as a function
FooFunctor func;
std::function<void (int)> f(func);
Здесь std::function
позволяет абстрагироваться от того, какой именно вызываемый объект вы имеете дело с — вы не знаете его FooFunctor
, вы просто знаете, что он возвращает void
и имеет один параметр int
.
Реальный пример, когда эта абстракция полезна, - это когда вы используете С++ вместе с другим языком сценариев. Возможно, вы захотите создать интерфейс, который может совместно использовать обе функции, определенные в С++, а также функции, определенные на языке сценариев.
Изменить: Связывание
Наряду с std::function
вы также найдете std::bind
. Эти два являются очень мощными инструментами при совместном использовании.
void func(int a, int b) {
// Do something important
}
// Consider the case when you want one of the parameters of `func` to be fixed
// You can used `std::bind` to set a fixed value for a parameter; `bind` will
// return a function-like object that you can place inside of `std::function`.
std::function<void (int)> f = std::bind(func, _1, 5);
В этом примере объект функции, возвращаемый bind
, принимает первый параметр _1
и передает его в func
в качестве параметра a
и устанавливает b
как константу 5
.
Они совсем не то же самое. std::function
- сложный, тяжелый, сдержанный, почти магический тип, который может содержать любой вызываемый объект, а указатель функции - просто простой указатель. Если вам это удастся, вы должны выбрать либо голой указатель функции, либо auto
- bind
/auto
-lambda. Используйте только std::function
, если вам действительно нужен систематический способ организации гетерогенной коллекции вызываемых объектов, таких как функции, функторы, захват lambdas и выражения bind.
Обновление: Немного о типах auto
: Сравните следующие две функции:
void do_something_1(std::function<void(int)> f, int a) { f(a); }
template <typename F, typename A> void do_something_2(F f, A a) { f(a); }
Теперь представьте, что вы вызываете их с помощью выражения лямбда или bind
:
do_something_X([foo, &bar](int n){ bar += n*foo; }, 12);
do_something_X(std::bind(X::bob, &jim, true, _1, Blue), 13);
Вторая версия с шаблоном более эффективна, поскольку в обоих случаях аргумент F
выводится на фактический, непознаваемый тип выражения. Первая версия с std::function
не является шаблоном и может выглядеть более простым и преднамеренным, но она всегда создает конструкцию объекта std::function
и, возможно, переносит затраты на стирание и виртуальную доставку нескольких типов.
A std::function
имеет состояние. Он может содержать дополнительные параметры, связанные с ним.
Эти параметры могут варьироваться от таких вещей, как другие классы, другие функции или даже эти указатели на вызовы функций-членов.
Указатель функции замены не typedef int (*fn)(int);
Это typedef int (*fn)(void*,int);
, при этом void*
регенерирует состояние, которое будет скрыто в std::function
.
Нет.
Один - это указатель на функцию; другой - объект, который служит в качестве обертки вокруг указателя функции.
Они в значительной степени представляют одно и то же, но std::function
намного мощнее, что позволяет делать привязки и многое другое.