Reputation: 1749
I have a series of member functions that are all very similar, and I think I might be able to make my code more maintainable with a template or some other approach, but I am not sure how to do it.
Here is an example of one of my functions:
void CalController::bgc_cmd(const std::string& s) {
try {
this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
My other functions are identical except for:
bgc_cmd(..)
, env_cmd(..)
, dsl_cmd(..)
md
class) that is called within the try...catch
blockEssentially I'd like to avoid having to duplicate the try..catch
block and LOG(..)
message in each of my CalController::XXX_cmd(...)
functions.
Using boost::function
and or boost::bind
would be fine, I am just going in circles and can't figure out how to set this up.
Upvotes: 1
Views: 62
Reputation: 6005
If using C++11, You can create a function with a more generic name, let's say exex_cmd
.
You can then pass a lambda function as argument and execute it inside the try/catch block - no need for a template use.
//WARNING: Untested code - the point is that you get the idea. Modify at will.
void CalController::exec_cmd(const std::function<void (void)> func) {
try {
//Invoke lambda.
//The string is passed via closure implementation,
//but you can always pass it as normal argument if you want.
func();
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Then, create 3 wrapper methods, invoking exec_cmd
, but passing a different lambda as argument:
void CalcController::bgc_cmd(const std::string& s){
CalcController::exec_cmd([=] () {
//Taking closures into control, to avoid passing the string as argument.
this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));
})
}
void CalcController::env_cmd(const std::string& s){
CalcController::exec_cmd([=] () {
//different function invocation here.
})
}
Similarly, you can do it for all your functions.
You can look here for more about C++11's lambdas.
A similar approach in plain-old C++ is to define a function pointer type and pass a function pointer to your exec_cmd
, create normal functions following the type signature and pass them as arguments, or pass a member function pointer - You can look at Barry's answer for that.
Upvotes: 1
Reputation: 9953
I think you can get what you want with a simple, regular function. No need for a template:
void CalController::do_cmd(boost::function<void (String)> fun, const std::string& s) {
try {
fun(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Then you can make your other methods something like:
void CalController::bgc_cmd(const std::string& s) {
// here TypeOfMd is whatever the type is for this->cohort_ptr->md.
// This binds the "this pointer" for set_bgcmodule to this->cohort_ptr->md
do_cmd(boost::bind(&TypeOfMd::set_bgcmodule, this->chort_prt->md), s);
}
A few things to note here:
Upvotes: 1
Reputation: 302852
You could just write a member function to do all that stuff. No bind
or template necessary since everything is a function on md
that takes the same argument type. I'm going to use MD
as the type of md
, and I'm assuming onoffstr2bool
returns a bool
:
void set_cmd(void (MD::*fn)(bool), const std::string& name, const std::string& s)
{
try {
(this->cohort_ptr->md->*fn)(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned " << name << " to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Which you would then call like:
void CalController::bgc_cmd(const std::string& s) {
set_cmd(&MD::set_bgcmodule, "bgc module", s);
}
Upvotes: 2