'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」が 2 回指定されていることに注意してください。ここでは冗長に見えます。
そこで知りたいのは、テンプレート パラメーターClassTypeを回避できるかどうかです。たとえば、メンバー関数のポインター パラメーターから暗示または抽出できる場合は、Wrapper<> のインスタンス化で明示的に指定する必要はありません。
同様に、(おそらく) 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++11 ではなく C++03 を使用していますが、C++11 が提供するものについても知りたいと思っています。
編集: 詳細 - このメカニズムを使用して ~300 のメンバー関数 (すべて ClassType に属するか、非常に類似したクラスのセット) をラップするつもりですが、考慮すべきシグネチャは約 6 つしかありません。
- void (ClassType::Function)(ArgType) - ArgType は「フローティング」です
- void (ClassType::Function)(ArgType) - ArgType は「整数」です
- void (クラスタイプ::関数)(ブール値)
- void (ClassType::Function)(IndexType, ArgType) - 追加の 'index' 引数を持つ上記の 3 つ
メンバー関数は、たとえば、(上記の単純な 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