(別の言語から) C++ 関数をラップする一般的な方法を作成しようとしています。パラメーター (および反復子) のリストと、パラメーターのリストで呼び出される特定の C++ 関数があります。パラメータのリストを関数の引数としてアンパックする方法を見つけようとしています。
私の現在のアプローチは次のとおりです。
- Boost::FunctionTypes を使用して、関数のパラメーターをシーケンスとして取得します。
- キャスト用のパラメータ タイプの値を使用して、引数の値を含む Boost::Fusion リストを作成します。
- boost::fusion の呼び出しを使用して、作成されたリストで関数を呼び出します。
手順 (1) と (2) はどちらもかなり簡単に実行できるようです。ただし、2 番目のステップを実行する方法がわかりません (または、それが可能な場合でも、コンパイル時と実行時の混合は少し奇妙に思えます)。
2番目のステップを実行する方法、またはこの問題に対するより良いアプローチを知っている人はいますか?
Boost::Python が似たようなことをしなければならないことは知っていますが、何が起こっているのかをよく理解するために、コードは少し複雑です。
アップデート
(少なくとも)単純なケースで機能する部分的な解決策があります。参照の処理にはまだ問題があります。
うまくいけば、誰かがより良い解決策を投稿できます。
リストには基本クラス A へのポインターが含まれており、そこから使用される他のすべてのクラスが派生します。異なる値の型 (int と string) を含む 2 つのサブクラス B と C があります。
演算子 convert は、指定されたクラスを取り、基になる値を取得します。これらの値は、呼び出しに渡されるシーケンスに変換することによって収集されます。
class A {
public:
A() {}
virtual ~A() {}
};
class B: public A {
protected:
int value;
public:
B() {}
B(int v): value(v) {}
int getValue() { return value; }
};
class C: public A {
protected:
string value;
public:
C() {}
C(const string &v): value(v) {}
string &getValue() { return value; }
};
// this pattern was copied from the test files from the fusion library
struct convert {
// keep a reference to the parameter we're going to unpack
list<A *>::iterator ¶m;
convert(list<A *>::iterator ¶m): param(param) {}
template<typename Sig>
struct result;
template <typename T>
struct result<convert(T)> {
typedef T type;
};
// this must be specialized in order to properly deal with the return types
template <typename T>
T operator ()(T type) const {}
};
template <>
int convert::operator ()(int type) const {
B *b = dynamic_cast<B *>(*param++);
if (b != NULL) return b->getValue();
throw error("illegal cast");
}
template <>
string convert::operator ()(string type) const {
C *c = dynamic_cast<C *>(*param++);
if (c != NULL) return c->getValue();
throw error("illegal cast");
}
最後に、関数を呼び出すには:
// create a parameter list (usually this would be passed to us)
list<A *> params;
params.push_back(new B(2));
params.push_back(new C("test"));
// point to beginning of parameter
list<A *>::iterator pos = params.begin();
// foo is the function we're going to call,
typedef BOOST_TYPEOF(foo) params_type;
// use the parameter list of foo to unpack the parameter list
auto passedParams = fusion::as_list(fusion::transform(function_types::parameter_types<params_type>(), trans(pos)));
// finally, call foo with the sequence that was created by the transform
fusion::invoke(foo, passedParams);