2009-07-15 6 views
6

私は基本的にタイプを手動で指定することなくジェネリックC関数のラッパーを生成したいと考えています。だから私は固定プロトタイプのコールバックを持っているが、私はラップされた関数の型に基づいてラッパーでいくつかの特別なコードを行う必要があるだろう...だから、基本的に私はクラステンプレートタイプのないテンプレートパラメータ...これがテンプレートです! (C++)

// this is what we want the wrapped function to look like 
typedef void (*callback)(int); 
void foobar(float x); // wrappee 

// doesn't compile 
template< T (*f)(S) > // non-type template param, it's a function ptr 
struct Wrapper 
{ 
    static void wrapped(int x) 
    { 
    // do a bunch of other stuff here 
    f(static_cast<S>(x)); // call wrapped function, ignore result 

    } 
} 

をそして私のような何かをしたいと思います:準拠したインタフェースなどに私の機能をラップする

AddCallback(Wrapper<foobar>::wrapped); 

しかし、問題は、私はちょうど先にして使用行くことができないということですWrapperテンプレートの関数のパラメータに "S"が含まれている場合は、最初にパラメータとして指定する必要があります。

template< class T, class S, T (*f)(S) > 
struct Wrapper 
// ... 

しかし、これは、()を使うのがもっと苦痛だということを意味します。理想的には、そこに関数ポインタを渡して、パラメータの型(および戻り値の型)を自動的に調整してください。明らかにするために、ラップされた関数の中で関数ポインタの型を参照する必要があります(したがって、私はSまたはTと同等のものが必要です)。

これを行う方法はありますか?

+0

@ damndirtyape:私はあなたの質問について考えてきました。私は似たようなことをやったと思います。残念ながら、それは多くのコードを含んでいました。基本的には、私のソリューションはoperator()をオーバーロードした基底クラスを持ち、渡された関数型に基づいて基底クラスを構築するファクトリ関数を持っていました。あなたが好きなのであれば、どこかのペーストビンにコードを掲載することができます。 –

答えて

0

"ラップされた"関数を使用して直接参照するのではなく、コンパイラは関数呼び出しのテンプレートパラメータを自動的に一致させようとします。

編集:これはどうですか?

int foobar(float x); // wrappee 

template <typename T, typename S> 
struct Wrapper { 
    typedef T (*F)(S); 
    F f; 

    Wrapper(F f) : f(f) { } 

    void wrapped(S x) { 
     // do a bunch of other stuff here 
     f(x); // call wrapped function, ignore result 
    } 
}; 

template <typename T, typename S> 
Wrapper<T,S> getWrapper(T (*f)(S)) { 
    return Wrapper<T,S>(f); 
} 

... 
getWrapper(foobar).wrapped(7); 
+0

これは問題を解決しません。なぜなら、その関数のテンプレートパラメータに同じ問題があるからです。 – damndirtyape

+0

本当ですか?たぶん私はあなたがしようとしていることを理解していないかもしれません... –

+0

関数を静的メソッドからインスタンスメソッドに変更したので動作しませんが、全体のポイントはラップされた関数を既存のコールバックシグネチャ(これは静的でなければならないことを意味します)。 – damndirtyape

0

EDIT:全く新しい回答

OK、私は完全に質問を再度考えて、私はあなたが望む結果を得ると信じていました。私は実際にこれを前にしました: - P。

ここに、私はoperator()をオーバーロードするBaseクラスを持っています。次に、関数の "アーリティ"ごとにサブクラスがあります。最後に、私はこれらのものの1つを返すファクトリ関数を持っています。コードは大きく(おそらく少し残酷すぎる)、うまく機能します。 library_functionのオーバーロードの大部分は、ほとんどの場合不要なさまざまな構文をサポートすることです。また、おそらく必要以上に多くの機能、メンバー関数などをboost::bindでサポートしています。

http://pastebin.com/m35af190

例、使用法は:

// map of library functions which will return an int. 
std::map<std::string, LibraryFunction<int> > functions; 

// function to register stuff in the map 
void registerFunction(const std::string &name, LibraryFunction<int> func) { 
    functions.insert(std::make_pair(name, func)); 
} 

後であなたはこれを行うことができます。

// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out 

// register 2 functions, one with no params, one with 1 param 
registerFunction("my_function", library_function1(*this, call_my_function)); 
registerFunction("my_function2", library_function0(*this, call_my_function2)); 

functions["my_function"](); 
functions["my_function2"](); 
+0

これは私が既存の関数をラップすることはできません。新しいオブジェクトを書く必要があります。つまり、型を推測させるのではなく、前もって指定する必要があります。 – damndirtyape

+0

私はそれが私にどのように役立つか分かりません。基本的に私は特定のコールバックシグネチャを持っています(私はコントロールできません)。このコールバックシグネチャに従うために、多数の既存のC関数をラップする必要があります(スクリプトバインディングなので、スタックから3つの値を取り出し、それらをラッパに渡し、結果をスタックにプッシュします - しかし、外部的にはすべての関数は全く同じシグネチャを持ちます)。 – damndirtyape

+0

もう、それは私を助けません。固定のコールバック署名と互換性のある関数ポインタに変換する必要があります。これはそうしない。関数内でいくつかの魔法(ストリングをスタックなどにプッシュする)を行うことで、コールバックに対応する関数に文字列(関数)を渡す必要がありますが、このラップ関数*のシグネチャは、コールバックに対応します。 – damndirtyape

0

私はブーストを見て思います。あなたの質問の最初の読書では、私には<boost/function_types/parameter_types.hpp>よりあなたの必要性を提供するようです。

+0

本当に良い答えではありません。少なくとも、関係するブーストライブラリを指さなければ、「Googleで検索してください、答えはそこにあると思います」と言います。さらに、OP要件を満たすことができるBoostには何も表示されません。あなたはあなたの答えでより具体的になりますか? –

+0

私は持っていた。私は直接HTMLエンティティの代わりに<と>を使っていて、ヘッダー名は隠されていました。私はそれを修正するために私の答えを編集しました。 – AProgrammer

+0

コメントでは、エンティティは必要なく、< and >が動作します...私はまだインターフェイスを学習しています。 – AProgrammer

5

ランタイムに適切なトランポリン機能を生成するためにLLVMなどを使用することを検討してください。または、ここには静的解があ​​ります。

#include <iostream> 

void f(float f) { std::cout << f << std::endl; } 

template<typename T, typename S> struct static_function_adapter { 
     template<T(*f)(S)> struct adapt_container { 
       static void callback(int v) { 
         f(static_cast<S>(v)); 
       } 
     }; 

     template<T(*f)(S)> adapt_container<f> adapt() const { 
       return adapt_container<f>(); 
     } 
}; 

template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) { 
     return static_function_adapter<T, S>(); 
} 

#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback) 

int main() { 
     void (*adapted)(int) = ADAPTED_FUNCTION(f); 
     adapted(42); 
     return 0; 
} 

get_adapter関数を使用すると、引数と戻り値の型を推論できます。 adapt()は、これを実際の関数でパラメータ化された型に変換し、最後にコールバックで静的関数を取得します。

+0

私はこのコードが何をすべきか、そしてそれが解決すべき問題についてちょっと考えていません。 – Virus721

関連する問題