Ric*_*Liu 5 c++ function-object
我正在设计一种机制,它将按顺序执行一组一元函数对象.这些函数对象在运行时分配,问题是:这些函数对象的参数类型不同.
我想做的是这样的:
class command_sequence {
private:
/* some kind of container */
public:
void add( FUNC_OBJ &func, PARAM val );
void run(void);
};
class check_temperature {
public:
void operator() (int celsius) {
if(celsius > 26) {
cooler.switch_on();
}
}
};
class log_usage {
public:
void operator() (std::string username) {
username.append(" logged in");
syslog(LOG_NOTICE,username.c_str());
}
};
command_sequence sequence;
log_usage logger;
check_temperature checker;
sequence.add(logger, std::string("administrator"));
sequence.add(checker, lobbyMeter.read_temperature());
sequence.add(logger, std::string("lecture"));
sequence.add(checker, classroomMeter.read_temperature());
sequence.run();
Run Code Online (Sandbox Code Playgroud)
如果我正在编写C代码,我别无选择只能将void*作为参数的回调函数指针.但我现在正在使用C++,应该有一种优雅的方式来处理它.
我现在能想到的最好方法是声明一个虚拟继承自抽象包装类的模板类:
class command_sequence {
private:
class runner {
public:
virtual void execute(void) = 0;
};
template <class FUNC, typename T> class func_pair : public runner {
private:
FUNC &func;
T param;
public:
func_pair(FUNC &f, const T &t) : func(f),param(t) { }
void execute(void) {
func(param);
}
};
std::vector<runner*> funcQueue;
public:
template <class FUNC, typename T> void add(FUNC &obj, const T &t) {
funcQueue.push_back( new func_pair<FUNC,T>(obj,t) );
}
void run(void) {
std::vector<runner*>::iterator itr=funcQueue.begin();
for(;itr!=funcQueue.end();++itr) {
(*itr)->execute();
delete (*itr);
}
}
};
Run Code Online (Sandbox Code Playgroud)
这种方法可以满足我的需求,但它会为每个条目分配和释放template_pair.我不知道这是否会导致内存碎片,因为在此过程中会非常频繁地调用此过程.
有没有更好的方法来做到这一点?
你真的需要分别传递一个函数对象及其参数吗?我会使用boost::bind,在这种情况下,它可能如下所示:
void check_temperature( int celsius )
{
if(celsius > 26) {
cooler.switch_on();
}
};
void log_usage( std::string username )
{
username.append(" logged in");
syslog(LOG_NOTICE,username.c_str());
};
// keep actions
typedef std::vector< boost::function<void()> > func_arr_t;
func_arr_t actions;
actions.push_back( boost::bind( &log_usage, "administrator" ) );
actions.push_back( boost::bind( &check_temperature, lobbyMeter.read_temperature() ) );
actions.push_back( boost::bind( &log_usage, "lecture" ) );
actions.push_back( boost::bind( &check_temperature, classroomMeter.read_temperature() ) );
// run all
for ( func_arr_t::const_iterator it = actions.begin(); it != actions.end(); ++it )
(*it)();
Run Code Online (Sandbox Code Playgroud)
在这种情况下,command_sequence只保留一个函数对象的数组.
小智 4
由于一元函数的参数在将其添加到序列时似乎是固定的,因此您可以使用boost::function使序列接受零参数函数对象,然后boost::bind所需的参数,例如
class command_sequence {
public:
void add( boost::function<void(void)> functor );
};
/* ... as before ... */
log_usage logger;
check_temperature checker;
sequence.add( boost::bind<void>(logger, "administrator") );
sequence.add( boost::bind<void>(checker, lobbymeter.read_temperature()) );
Run Code Online (Sandbox Code Playgroud)
请注意,您必须指定<void>为调用的模板参数,boost::bind因为它无法自动推断函数对象的返回类型。result_type或者,您可以公开在类定义中调用的公共 typedef 来避免这种情况,即
class log_usage
{
public:
typedef void result_type;
void operator() (const std::string& message)
{
// do stuff ...
}
};
/* ... */
sequence.add(boost::bind(logger, "blah")); // will now compile
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
797 次 |
| 最近记录: |