在没有实例的情况下调用无状态lambda(仅限类型)

eno*_*ram 4 c++ lambda template-meta-programming variadic-templates c++11

我正在尝试从C库为"寄存器回调"类型的接口编写一个包装器.这个问题非常复杂,因为库允许您通过接受参数定义列表来注册"可变参数"函数.然后在回调时,该函数应该从类型擦除的参数列表中提取其参数.好老C ...

我正在尝试创建的接口是接受任何函数,甚至是lambda,并自动生成所有机制以正确注册此函数,同时注册参数并在回调时提取它们.因此用户只需键入:

register_callback("Callback Name", [](int i){return i+0.5;});
Run Code Online (Sandbox Code Playgroud)

现在这在理论上是可行的,但是在某一点上,我需要能够在没有任何实例的情况下调用lambda,但只能访问它的类型.我不明白为什么,但是无状态(非捕获)lambda的默认构造函数被删除,所以我不能简单地从它的类型默认构造.我打算做的事情看起来很脏,但应该可以解决这个问题:

template <class Func, class RET, class ...ARGS>
struct from_stateless {
    static RET to_function(ARGS...args) {
        RET (*f)(ARGS...) = *(Func *)(0);
        return f(args...);
    }
};
Run Code Online (Sandbox Code Playgroud)

所以这from_stateless<LAMBDA_TYPE, RET, ARGS...>::to_function实际上是一个函数指针,我可以在没有参数的情况下调用,更重要的是我可以作为模板参数传递的函数指针.

在正常情况下,线路RET (*f)(ARGS...) = *(Func *)(0);会自杀,但这个用例确实应该是安全的,不是吗?毕竟,转换后获得的函数指针不能在任何可能依赖于lambda实例的Universe中.

所以,问题是,只要我确保该类型确实是无状态lambda,这样做是否安全?或者我错过了什么?请注意,RET (*f)(ARGS...) = *(Func *)(0);如果闭包意外滑过,则会触发编译器错误.

澄清:我不能将lambda衰减为函数指针并注册它,因为lambda的签名与"Register"方法不兼容.register方法需要一个带签名的函数:void (*)(int number_of_args, TypeErasedValue * arguments, TypeErasedValue * result)所以你看,我需要(并且已经做过),通过模板元编程,生成一个模板化lambda类型的自由函数,作为预期签名和实际签名之间的适配器.

Okt*_*ist 6

如果你利用lambda可以看到static其封闭范围的本地而不需要捕获它们这一事实,它甚至比@ Yakk的答案更容易.使用此事实,您可以使用所需的签名将用户提供的无状态lambda包装在您自己的无状态lambda中,并将后者转换为函数指针.

using callback = void (*)(int, TypeErasedValue*, TypeErasedValue*);

template <typename F>
callback stateless_to_callback(F f) {
    static F static_f = f;
    return [](int argc, TypeErasedValue* argv, TypeErasedValue* result) {
        // extract arguments from argv
        auto r = static_f( /* arguments... */ );
        // store r in result
    };
}
Run Code Online (Sandbox Code Playgroud)