1

私は、関数呼び出しを 2 つの規則の間で変換する C++11 テンプレート関数を作成する方法を理解しようとしています。 DoubleVariant など)、2 つ目は C 関数呼び出しです。

コンパイル時にすべての情報を知っています。引数の数はパラメーターの数であり、引数/戻り値の型は 'cfunc' 変数の型に依存します。

// We will assume that the two following functions are defined with their correct
// specializations.

template < typename T >
Variant * convertToVariant( T t );

template < typename T >
T convertFromVariant( Variant * variant );

// The following function is incomplete, the question is how to convert the
// variant parameters into a C function call ?

template < typename Return, typename... Arguments >
Variant * wrapCFunction< Return cfunc( Args... ) >(int argc, Variant ** argv) {
    // Here comes the magic call of cfunc, something like :
    if ( argc != mpl::count< Args... >::value )
        throw std::runtime_error( "bad argument count" );
    return cfunc( convertFromVariant< Args... >( argv[ X ] )... );
}

// Example use case :

int foo( int a, int b );

int main(void) {
    int argc = 2;
    Variant * argv[2] = { new IntVariant( 5 ), new IntVariant( 6 ) };

    Variant * res = wrapCFunction< foo >( argc, argv );
    IntVariant * intRes = dynamic_cast< IntVariant >( res );

    return intRes ? intRes->value : -1;
}
4

2 に答える 2

5

インデックス トリックを使用すると、これはかなり簡単です。

template<unsigned...> struct indices{};

template<unsigned N, unsigned... Is>
struct indices_gen : indices_gen<N-1, N-1, Is...>{};

template<unsigned... Is>
struct indices_gen<0, Is...> : indices<Is...>{};

// assuming the parameters were actually like this
template<typename Return, typename... Args, unsigned... Is>
Variant* wrapCFunction(Return (*cfunc)(Args...), int argc, Variant** argv, indices<Is...>) {
    return cfunc(convertFromVariant<Args>(argv[Is])...);
}

template<typename Return, typename... Args>
Variant* wrapCFunction(Return (*cfunc)(Args...), int argc, Variant** argv) {
    if (argc != sizeof...(Args))
        throw std::runtime_error("bad argument count");
    return wrapCFunction(cfunc, argc, argv, indices_gen<sizeof...(Args)>());
}

コードのいくつかの変更に注意してください。まず、sizeof...(Args)パック内の引数の数を生成します。次に、関数のシグネチャをcfunc実パラメータとして渡すように修正しました。

于 2012-10-07T02:00:35.080 に答える
2
class Variant;
template < typename T > Variant * convertToVariant( T t );
template < typename T > T convertFromVariant( Variant * variant );

template <typename Return, typename... Arguments>
struct WrapCFunctionImpl {
  template<int argsToAdd, int... argIndexes>
  struct Impl {
    typedef typename Impl<argsToAdd - 1, argIndexes..., sizeof...(argIndexes)>::Type Type;
  };
};
template <typename Return, typename... Arguments>
template <int... argIndexes>
struct WrapCFunctionImpl<Return, Arguments...>::Impl<0, argIndexes...> {
  typedef Impl Type;
  static Variant* run(Return cfunc( Arguments... ), Variant ** argv) {
    return convertToVariant( cfunc( convertFromVariant<Arguments>( argv[argIndexes] )... ) );
  }
};

template < typename Return, typename... Arguments >
Variant * wrapCFunction(Return cfunc( Arguments... ), Variant ** argv) {
    return WrapCFunctionImpl<Return,Arguments...>::template Impl<sizeof...(Arguments)>::Type::run(cfunc, argv);
}

int foo(int, int);
Variant *f(Variant** x) {
  return wrapCFunction(foo, x);
}

ここでの問題のほとんどは、配列にインデックスを生成するための再帰です。もっと簡単な方法があるかもしれませんが、これでうまくいきます。

于 2012-10-07T01:57:06.067 に答える