我想用模板类包装符合“void (ClassType::Function)(ArgType)”类型的成员函数。稍后,我想将 ClassType 的实例传递给此模板的实例并让它调用包装的方法:
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;
}
注意在 Wrapper<> 的实例化中“Foo”被指定了两次——在这里看起来是多余的。
所以我想知道的是是否可以避免模板参数ClassType。例如,如果可以从成员函数指针参数中隐含或提取它,则不需要在 Wrapper<> 的实例化中显式指定它。
以类似的方式,避免显式指定ArgType也很有用,因为(也许)它可以从 Foo::set?
这在 C++ 中可能吗?也许沿着这些(完全幻想的)路线:
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);
// ...
}
或者,也许可以调用另一个级别的模板魔术来执行以下操作:
Wrapper<Magic<&Foo::set> > wrapper(&foo);
我很想知道可能有哪些机制可用(如果有的话)。
我要求使用 C++03,而不是 C++11,但我也想知道 C++11 可能提供什么。
编辑:更多信息 - 我打算使用这种机制来包装约 300 个成员函数(全部属于 ClassType,或一组非常相似的类),但只有大约六个左右的签名需要考虑:
- void (ClassType::Function)(ArgType) - 其中 ArgType 是“浮动”
- void (ClassType::Function)(ArgType) - 其中 ArgType 是“积分”
- void (ClassType::Function)(bool)
- void (ClassType::Function)(IndexType, ArgType) - 上面三个带有额外的“索引”参数
例如,成员函数是我在大型配置“集合”类中称为“属性”的“设置器”函数(而不是上面的简单 Foo):
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