匿名函数C ++ [英] Anonymous function 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屋!