C ++ 0x lambda用于makecontext参数#2

时间:2011-07-24 21:34:46

标签: c++ c++11 lambda

我无法将C ++ 0x lambda函数作为第二个参数传递给makecontext(来自ucontext.h)。 makecontext的签名是:

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

之前,我能够将C风格的(void (*)(void))强制转换应用于我使用的全局范围函数。 reinterpret_cast可以在C ++中实现这一功能。但是,使用C ++ 0x lambda函数,我收到以下错误:

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 个答案:

答案 0 :(得分:6)

[](int i){}是一个无捕获的lambda,它有一个int参数并且什么都不返回;因此它可以隐式转换为void(*)(int):指向一个函数的指针,该函数只接受一个int并且不返回任何内容。

假设makecontext函数能够处理不同类型的函数(从文档中可以看出,虽然文档有点模糊),那么你需要使用两个强制转换才能使用它使用lambda:一个将lambda转换为函数指针,另一个将lambda转换为void(*)()类型:

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

这一切都相当不安全(函数指针类型之间的转换并不是最安全的事情),所以最好将这种功能包装到实用程序库中。您可以使用函数模板包装makecontext函数,以便确保您对函数的所有使用都是类型安全的,并且所有不安全的代码都封装在一个地方。

答案 1 :(得分:1)

假设您已在示例中声明f2,并希望现在将其与makecontext一起使用。使用std::bind(在&lt; functional&gt;标题中找到)来生成一个可以像void(*)(void)一样调用的对象,而不是尝试强制转换它:

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

对象f3是一个可以在没有任何参数的情况下调用的函数对象。最终结果是f2最终被调用0作为其参数。如果您希望将不同的值传递给f2,则可以将其指定为bind的第二个参数。

修改

正如一些评论者指出的那样,这不适用于您的情况,因为makecontext需要一个实际的函数指针。所以,为了参考起见,我想我会指出你可能遇到的一个警告(如果你还不知道这个):使用lambda作为函数指针只有在你不使用闭包时才有效。一旦你关闭变量,lambda就不能再退化为函数指针,因为它可以没有闭包。

答案 2 :(得分:0)

您可以使用包装函数来包装它。 它适用于每一个lambda。 它背后的想法是,由于你不能将functor作为函数指针传递,你可以传递一个调用lambda函数的包装器函数。另一个技巧部分是我需要传递指针而不是整个对象,这是因为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...);
}