I would like to wrap member functions that conform to the type 'void (ClassType::Function)(ArgType)' with a templated class. Later, I want to pass an instance of ClassType to an instance of this template and have it invoke the wrapped method:
class Foo {
public:
Foo() : f_(0.0) {}
void set(double v) { f_ = v * 2.1; }
double get() { return f_; }
private:
double f_;
};
template <typename ArgType, typename ClassType, void (ClassType::*Method)(ArgType)>
class Wrapper {
public:
explicit Wrapper(ClassType *cls) : cls_(cls) {}
void do_something(ArgType value) {
(cls_->*Method)(value);
}
private:
ClassType *cls_;
};
#include <iostream>
int main(int argc, char ** argv) {
Foo foo;
Wrapper<double, Foo, &Foo::set> wrapper(&foo);
wrapper.do_something(1.0);
std::cout << foo.get() << std::endl;
// outputs "2.1"
return 0;
}
Notice in the instantiation of Wrapper<> that "Foo" is specified twice - it looks redundant here.
So what I'd like to know is whether it's possible to avoid the template parameter ClassType. For instance, if it is possible to imply or extract it from the member function pointer parameter, then it wouldn't need to be explicitly specified in the instantiation of Wrapper<>.
In a similar manner, it would be useful to avoid explicitly specifying ArgType also, as (perhaps) it can be determined from Foo::set?
Is this possible in C++? Perhaps something along these (entirely fantastical) lines:
template <void (ClassType::*Method)(ArgType)>
class Wrapper2 {
public:
explicit Wrapper(Method::ClassType *cls) : cls_(cls) {}
void do_something(Method::ArgType value) {
(cls_->*Method)(value);
}
private:
Method::ClassType *cls_;
};
// ...
int main() {
Foo foo;
Wrapper<&Foo::set> wrapper(&foo);
// ...
}
Or, perhaps there's another level of template magic that can be invoked that would do something along these lines:
Wrapper<Magic<&Foo::set> > wrapper(&foo);
I'm interested to know what mechanisms might be available, if any.
I'm using C++03 as a requirement, not C++11, but also interested to know what C++11 might offer.
EDIT: more info - I intend to use this mechanism to wrap ~300 member functions (all belonging to ClassType, or a set of very similar classes), but there will only be around six or so signatures to consider:
- void (ClassType::Function)(ArgType) - where ArgType is 'floating'
- void (ClassType::Function)(ArgType) - where ArgType is 'integral'
- void (ClassType::Function)(bool)
- void (ClassType::Function)(IndexType, ArgType) - the above three with an extra 'index' argument
The member functions are 'setter' functions for what I call "properties" in a large configuration 'collection' class, for example (rather than the simple Foo above):
class MyPropertyCollection {
public:
void set_oink(double value) { oink_ = value; }
void set_bar(int value) { bar_ = value; }
void set_squee(bool value) { squee_ = value; }
private:
double oink_;
int bar_;
bool squee_;
};
// elsewhere
WrapperCollection wrapper_collection; // a simple set of wrapper objects, accessed by id
MyPropertyCollection property_collection;
wrapper_collection.add(PROPERTY_OINK_ID, new Wrapper<double, MyPropertySet, &MyPropertySet::set_oink>(&property_collection);
wrapper_collection.add(PROPERTY_BAR_ID, new Wrapper<int, MyPropertySet, &MyPropertySet::set_bar>(&property_collection);
wrapper_collection.add(PROPERTY_SQUEE_ID, new Wrapper<bool, MyPropertySet, &MyPropertySet::set_squee>(&property_collection);
// +300 more