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

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

问题描述

我正在尝试使用 中的函数 signal(int,void(*)(int)) 来处理浮点异常 SIGFPE.除了仅显示浮点异常"或类似内容的消息之外,我还希望能够打印一些有用的诊断信息.这意味着我作为处理程序传递给 signal 的函数需要访问我的代码中的一些数据.这就是问题所在.

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.

该函数必须返回 void 并且只接受 1 个 int 类型的参数.由于隐藏的 this 指针,我无法使处理程序成为我的数据存储类的成员函数,因为那时类型将是 void(Foo::*)(int).

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.

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

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);});

然而,因为 lambda 从编译器外部捕获变量 data 不会让它被转换为指向 void(*)(int) 的指针(这是一个很遗憾,因为这似乎是 lambda 的理想用途).

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).

我可以简单地使 data 成为一个全局变量,然后可以在 handler 中看到它,但由于显而易见的原因,我不愿意这样做.

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.

所以我的问题是这样的;在 C++ 中模仿匿名函数的最佳方式是什么?

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

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

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

推荐答案

C 中没有匿名函数这样的东西(C++ 在这里无关紧要,因为函数必须遵守 C 调用约定).

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.

怎么做?

注意:正如 Luc Danton 耐心地向我解释的那样,信号可能会中断任何非原子活动,因此只有当它是无锁原子(或其他一些东西)时,从全局读取才是安全的.不幸的是,std::function 可能不是这样,这取决于您的实现,我仍然会留下这段代码来解释如何做到这一点前提是 std::function 访问是原子的.

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); }
}

以及以下 RAII setter:

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;
};

注意:全局变量和 handle_signal 都可以是 privateSignalSetter 类...但由于 std::signal 不是...

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

预期用途:

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天全站免登陆