匿名函数 C++ [英] Anonymous function 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
都可以是 private
到 SignalSetter
类...但由于 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屋!