Подтвердить что ты не робот

Могу ли я использовать функцию лямбда или объект std:: function вместо указателя функции?

У меня есть библиотека, которую мне нужно использовать, которая определяет следующее:

typedef void CallbackFunction(const int& i);

и имеет функцию регистрации вашего обратного вызова, который выглядит следующим образом:

void registerCallback(CallbackFunction* pCallback);

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

auto fCallback = [](const int& i) {
    cout << i << endl;
};
registerCallback(fCallback);

вместо этого я получаю ошибку:

error C2664: 'registerCallback' : cannot convert parameter 1 from '`anonymous-namespace'::<lambda0>' to 'CallbackFunction (__cdecl *)'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

Я много читал на эту тему и пытался несколько разных (возможно, идиотских) подходов, но я не могу заставить это работать. Выделение функции позволяет компилировать код, но (неудивительно) он сбой. Возможно, я упустил это решение либо здесь, в StackOverflow, либо в другом месте, поэтому ссылки хватит. (Хотя, поскольку я немного новичок в некоторых из этих методов, убедитесь, что корреспонденция достаточно понятна для новичков. Например, если этот разговор содержит мой ответ, я не понимаю. Пожалуйста, упростите или объясните корреспонденцию.) FYI, я использую Visual С++ 2010.

Пожалуйста, дайте мне знать, если я могу что-то сделать, чтобы уточнить мой вопрос. Заранее спасибо за помощь!

4b9b3361

Ответ 1

В общем, нет, вы не можете использовать объект лямбда или объект, где требуется указатель на функцию. Объектами функции являются полнофункциональные объекты, которые перегружают оператор приложения (()), поэтому вы можете использовать их как функции синтаксически.

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

Итак, чтобы объекты lambdas/function работали с вашим кодом, вам нужно будет изменить используемую вами библиотеку.

Ответ 2

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

Так как вы используете VS2010, вы не сможете. Особенность лямбда, которую вы пытаетесь использовать, не появилась до тех пор, пока не был выпущен VS2010: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3043.html

Так что, хотя да, он должен работать, на самом деле это не так.

Конечно, пока вы, на самом деле, не захватываете все, что вы заявляете, что хотите. Lambdas, которые захватывают данные, не могут быть преобразованы в указатели на функции даже в состоянии post VS2010 стандарта черновика С++.

Ответ 3

Короткий ответ: Нет

Длинный ответ:

Lamda - это просто синтаксический сахар для функторов.
Функторы - это объекты, которые действуют как функции.

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

Дополнительно:

С другой стороны, легко превратить функцию в функтор.

Исторически:

Указатели функций обычно используются библиотеками C. Поскольку библиотеки С++ будут использовать интерфейс для достижения такого же эффекта. Таким образом, вы можете понять, почему сложно передать функторы, где задан указатель на функцию (код C не имеет способа понять, как использовать функтор).

Ответ 4

Вы не можете использовать lambdas, потому что ваша функция registerCallback ожидает указателя на функцию, не являющуюся членом. Единственный способ передать дополнительный параметр для свободной стоящей функции: 1) использовать глобальные (статические) данные или 2) сделать его шаблоном с учетом констант времени компиляции, например

template<int data> void callback(const int& i)
{ /* can use data */ }

registerCallback(callback<10>);