匿名函数C ++ [英] Anonymous function C++

查看:258
本文介绍了匿名函数C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用信号(int,void(*)(int))从< csignal> 来处理浮点异常SIGFPE。我想打印一些有用的诊断,除了只是一个消息说浮点异常或某事。这意味着我作为处理程序传递给 signal 的函数需要访问我的代码中的一些数据。



函数必须返回 void ,并且只接受类型 int 。我不能让处理程序成为我的数据存储类的成员函数,因为类型将是 void(Foo :: *)(int)由于隐藏的<$ c $



我想过使用lambdas来尝试这样的匿名函数;

  void handler(int nSig,Foo data)
{
// do something
}
//
Foo data;
signal(SIGFPE,[&](int nSig) - > void {handler(nSig,data);});然而,因为lambda捕获变量 data ,所以



<从外部编译器不会让它转换为 void(*)(int)(这是一个耻辱,因为这似乎是一个理想的使用lambdas)的指针。



我可以简单地使 data 一个全局变量,然后可以在 / code>但我不愿意这样做是因为明显的原因。



所以我的问题是, 在C ++中模仿匿名函数的最佳方式

注意:我更喜欢使用本地C ++解决方案,而不必使用boost或等效的。

解决方案

在C中没有匿名函数这样的东西(C ++在这里是不相关的,因为函数必须遵守

只能从处理程序访问全局变量,可能是全局变量 / em>(而不是常数)。



我建议让这些全局变量线程本地避免多线程问题,






如何?



注意:正如Luc Danton耐心地向我解释的,信号可能会中断任何非原子活动,全局是安全的,只有当它是一个无锁的原子(或几个其他的东西)。 很遗憾, std :: function 可能不是这样,具体取决于您的实现,我仍然会留下此代码解释如何完成



这可能是因为 std :: function 创建一个蹦床,调用有状态的东西,隔离线程并允许重入调用。

  typedef std :: function< void (int)> SignalHandlerType; 

extern thread_local ignalHandlerType SignalHandler;

我们创建以下访问器(传递给信号):

  void handle_signal(int const i){
if(SignalHandler){SignalHandler(i); }
}

以及以下RAII设置器:

  class SignalSetter:boost :: noncopyable {
public:
SignalSetter(int signal,SignalHandlerType&& sh):
信号(信号),chandler(0),处理程序(sh)
{
chandler = std :: signal(signal,& handle_signal&
swap(SignalHandler,handler);
}

〜SignalSetter(){
std :: signal(signal,chandler);
Swap(SignalHandler,handler);
}

private:
typedef void(* CHandlerType)(int);

int signal;
CHandlerType chandler;
SignalHandlerType handler;
};

注意:全局变量和 handle_signal 可以私人 SignalSetter 类...但是因为 std: :signal 不是...



预期用途:

  int main(int argc,char * argv []){
SignalSetter setter(SIGFPE,[argc,argv](){
std :: cout< < argc<<:<< argc<< std :: endl;
}

//做你想要的。
}


I am trying to use the function signal(int,void(*)(int)) from <csignal> to handle the floating point exception SIGFPE. I'd like to be able to print some useful diagnostics besides just a message saying "Floating point exception" or something to that effect. This means the function I pass as the handler to signal needs access to some of the data in my code. Therein lies the rub.

The function must return void and accept only 1 parameter of type int. I cannot make the handler a member function of my data storage class since then the type would be void(Foo::*)(int) due to the hidden this pointer.

I thought about using lambdas to try and make an anonymous function like this;

void handler(int nSig, Foo data)
{
    // do something
}
// snip
Foo data;
signal(SIGFPE, [&](int nSig)->void{handler(nSig,data);});

however because the lambda captures the variable data from outside the compiler will not let it be cast to a pointer to void(*)(int) (which is a shame as this seems like an ideal use for lambdas).

I could simply make data a global variable which could then be seen in handler but I am loath to do this for obvious reasons.

So my question is thus; what is the best way of mimicking anonymous functions in C++?

Note: I would prefer a native C++ solution and not to have to use boost or equivalent.

解决方案

There is no such thing as an anonymous function in C (C++ is irrelevant here, as the function must abide by the C calling convention).

The only thing you can do is shiver access globals from the handler, probably global variables (and not constants which would be fine).

I advise making those globals thread local to avoid multithreading issues, but it is still bad in the sense that global variables make for more brittle applications.


How to ?

Note: as Luc Danton patiently explained to me, a signal may interrupt any non-atomic activity, and thus reading from a global is safe only if it is a lock-free atomic (or a few other things). Unfortunately std::function may not be so, depending on your implementation, I will still leave this code to explain how it could be done providing that std::function accesses are atomic.

It is possible to create a trampoline that will call stateful stuff, isolating thread and allowing re-entrant calls.

typedef std::function<void(int)> SignalHandlerType;

extern thread_local ignalHandlerType SignalHandler;

And we create the following accessor (passed to signal):

void handle_signal(int const i) {
    if (SignalHandler) { SignalHandler(i); }
}

as well as the following RAII setter:

class SignalSetter: boost::noncopyable {
public:
    SignalSetter(int signal, SignalHandlerType&& sh):
        signal(signal), chandler(0), handler(sh)
    {
        chandler = std::signal(signal, &handle_signal<T>);
        swap(SignalHandler, handler);
    }

    ~SignalSetter() {
        std::signal(signal, chandler);
        swap(SignalHandler, handler);
    }

private:
    typedef void(*CHandlerType)(int);

    int signal;
    CHandlerType chandler;
    SignalHandlerType handler;
};

Note: both the global variable and the handle_signal could be private to the SignalSetter class... but since std::signal is not...

Expected usage:

int main(int argc, char* argv[]) {
    SignalSetter setter(SIGFPE, [argc, argv]() {
        std::cout << argc << ": " << argc << std::endl;
    });

    // do what you want.
}

这篇关于匿名函数C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆