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

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

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, либо где-то еще, поэтому ссылка будет достаточной. (Хотя, поскольку я немного новичок в некоторых из этих методов, пожалуйста, убедитесь, что переписка достаточно ясна для новичка. Например, если этот разговор содержит мой ответ, я не понимаю Пожалуйста, упростите или объясните соответствие.) К вашему сведению, я использую Visual C ++ 2010.

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

Ответы [ 4 ]

8 голосов
/ 22 января 2011

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

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

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

7 голосов
/ 22 января 2011

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

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

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

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

4 голосов
/ 22 января 2011

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

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

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

Указатель на функциюэто не то же самое.Как правило, вы не можете использовать функторы, если вам нужен указатель на функцию.

Extra:

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

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

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

0 голосов
/ 22 января 2011

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

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

registerCallback(callback<10>);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...