C ++ 0x лямбда для аргумента makecontext # 2 - PullRequest
5 голосов
/ 25 июля 2011

У меня возникают проблемы при передаче лямбда-функции C ++ 0x в качестве второго аргумента makecontext (из ucontext.h). Подпись makecontext:

void makecontext(ucontext_t*, void (*)(), int, ...);

Ранее я мог применять приведение в стиле C (void (*)(void)) к функциям глобальной области видимости, которые я использовал. A reinterpret_cast сделает то же самое в C ++. Однако с лямбда-функцией C ++ 0x я получаю следующую ошибку:

error: invalid cast from type ‘main(int, char**)::<lambda(int)>’ to type ‘void (*)()’

Я использую G ++ 4.6. Для получения ошибки компиляции достаточно следующего кода:

#include <ucontext.h>

void f1(int i) {}

int main(int argc, char *argv[]) {
  ucontext_t c;
  makecontext(&c, (void (*)(void))f1, 1, 123); // ok
  makecontext(&c, reinterpret_cast<void (*)(void)>(f1), 1, 123); // ok

  auto f2 = [](int i){};
  makecontext(&c, (void (*)(void))f2, 1, 123); // error
  makecontext(&c, reinterpret_cast<void (*) (void)>(f2), 1, 123); // error
  return 0;
}

Ответы [ 3 ]

6 голосов
/ 25 июля 2011

[](int i){} - лямбда без захвата, которая имеет единственный параметр int и ничего не возвращает; таким образом, он неявно преобразуется в void(*)(int): указатель на функцию, которая принимает один int и ничего не возвращает.

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

auto f2 = [](int i) { };
makecontext(&c, (void (*)(void))(void (*)(int))f2, 1, 123);

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

1 голос
/ 25 июля 2011

Допустим, вы уже объявили f2, как в своем примере, и хотите использовать его сейчас с makecontext.Вместо того, чтобы пытаться разыграть его, используйте std::bind (находится в заголовке ), чтобы создать объект, который можно вызвать как void(*)(void):

auto f3 = std::bind(f2, 0);
makecontext(&c, f3, 1, 123);

Объект f3 является функциейобъект, который можно вызвать без каких-либо аргументов.Конечным результатом является то, что f2 в итоге вызывается с 0 в качестве аргумента.Если вы предпочитаете, чтобы другое значение было передано f2, вы можете указать его в качестве второго аргумента для bind.

Редактировать

Как указали несколько комментаторов, это не 'Это применимо в вашем случае, так как makecontext требует фактического указателя на функцию.Итак, для справки, я подумал, что хотел бы указать на одну оговорку, с которой вы можете столкнуться (в случае, если вы этого еще не знаете): использование лямбды в качестве указателя на функцию работает, только если вы не используете замыкания.Как только вы закрываете переменные, лямбда больше не может вырождаться в указатель на функцию, как это может происходить без замыкания.

0 голосов
/ 05 июля 2014

Вы можете использовать функцию обертки, чтобы обернуть ее. Это работает для каждой лямбды. Идея заключается в том, что, поскольку вы не можете передать функтор как указатель на функцию, вы можете передать функцию-обертку, которая вызывает функцию лямбда-выражения. Еще одна хитрость в том, что мне нужно передать указатель вместо всего объекта, потому что makecontext может принимать только аргументы типа int.

template<typename Kernel, typename ...Args>
void wrapper(Kernel *ker, Args*... args)
{
    (*ker)(*args...);
}
template<typename Ker, typename ...Args>
void makectx(Ker ker, Args... args)
{
    makecontext(&ctx, (void (*)(void))wrapper<Ker, Args...>, sizeof...(Args) + 1, &ker, &args...);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...