dav*_*idA 7 c++ templates member-function-pointers template-meta-programming
我想用模板化的类包装符合'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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,在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);
// ...
}
Run Code Online (Sandbox Code Playgroud)
或者,也许还有另一个级别的模板魔法可以被调用,可以沿着这些方向做一些事情:
Wrapper<Magic<&Foo::set> > wrapper(&foo);
Run Code Online (Sandbox Code Playgroud)
我很想知道可能有哪些机制,如果有的话.
我使用C++ 03作为要求,而不是C++ 11,但也有兴趣知道C++ 11可能提供什么.
编辑:更多信息 - 我打算使用这个机制来包装~300个成员函数(都属于ClassType,或一组非常相似的类),但只有大约六个左右的签名需要考虑:
例如,成员函数是我在大型配置'集合'类中称为"属性"的"setter"函数(而不是上面的简单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
Run Code Online (Sandbox Code Playgroud)
::std::mem_fn
这是+的一个糟糕的重新实现::std::bind
,它是 C++11 结构。您可以使用以下方法来执行此操作:
#include <functional>\n\nint main() {\n Foo foo;\n auto wrapper = ::std::bind(::std::mem_fn(&Foo::set), ::std::ref(foo), _1);\n wrapper(5); // Calls foo.set(5)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n但是,当然,您需要 C++03 解决方案。使用 Boost 可以在 C++03 中实现这一点。我也相信在 C++03 和 TR1 中类似的事情是可能的。您可以通过查看是否#include\xc2\xa0<tr1/functional>
有效来判断您是否拥有该功能。如果您有 TR1,它们会显示在::std::tr1
名称空间中。
现在,有一种方式却并非如此。您已将函数指针本身作为类类型签名的一部分。这是一件奇怪的事情,但正如您所知,这肯定是可能的。不过,能够在编译时确定ClassType
和值是很棘手的。ArgType
您可以通过模板函数参数匹配来做到这一点,但没有用,因为 C++03 没有auto
.