2009-09-04 6 views
1

this answerを読んだ後、私は解決策があると思いました。少なくとも答えは私がしたいことですが、私は実装に問題があります。 ()f.targetから返さここboost :: function :: targetを使用して関数ポインタを取得するときにnullポインタ

は私が

typedef map<string, double*> myMap; 
typedef int (*ftwpt)(const char*, const struct stat*, int); 
typedef boost::function<int(const char*, const struct stat*, int)> MyFTWFunction; 

int myFunction(const char*, const struct stat*, int, myMap*); 

int main() 
{ 
myMap m_map; 
char tmpdir[] = "/tmp/mytmp"; 

MyFTWFunction f = boost::bind(myFunction,_1,_2,_3, &m_map); 

ftwpt* fpt = f.target<ftwpt>(); 
if (fpt) 
    status = ftw(tmpdir, *fpt, 50); 
else 
{ 
    cout << "Boost could not perform runtime conversion on function pointer" << endl; 
    return (EXIT_FAILURE); 
} 
} 

プログラムはエラーや警告なしでコンパイルが、私は、NULLポインタ(FPT)を取得していますがやろうとしています何の概要です。実行時に上記のstackoverflowの質問にリンクされている参照から、ブーストが実行時変換を実行できない場合はnullポインタが返されるようです。しかし、私はBoostがなぜランタイム変換を実行できないのか分かりません。何か案は?

+0

@Konradあなたのコードが失敗した理由も説明しています:ここで読むhttp://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer/512233 #512233 –

+0

@HazyBlueDot - この質問はCではなく、Cであり、正しくはタグ付けしてください。 –

答えて

2

これを実行するには、boost::functionオブジェクトに格納するバインド式の正確なタイプを知る必要があります。オブジェクトboost::bind(....)は、関数ポインタではなく、奇妙な表現テンプレートです。ずっとboost::anyのように -

はこれが必要な理由、関数は operator()肥大化せず、原則として最も基本的な構造です

struct base { virtual ~base() { } }; 

template<typename T> 
struct derived : base { 
    derived(T t):t(t) { } 
    T t; 
}; 

struct function { 
    template<typename T> 
    function(T t) { 
    base *b = new derived<T>(t); 
    } 

    template<typename T> 
    T *target() { 
    if(typeid(*b) == typeid(derived<T>)) 
     return &static_cast< derived<T>* >(b)->t; 
    return 0; 
    } 

    base *b; 
}; 

に実装されている方法を後押し::検討し理解するために。このメカニズムは型消去と呼ばれます。コンストラクタは任意の型のオブジェクトを受け入れ、仮想関数呼び出しによって到達できるオブジェクトにカプセル化されたオブジェクトを格納します(boost::functionは、独自のvtableとスタック割り当てを使用して地獄のように最適化されます小さいタイプの場合はnewなど)。

boost::functionオブジェクトに割り当てた関数の型を知っているので、関数ポインタについては、これが有効です。しかし、複雑な呼び出し可能なオブジェクトの場合、それはもううまく動作しません。

は、それが働いて見て、それが単なる関数ポインタではなく、バインド式での作業いないことを確認するために、あなたは何をboost::bindリターンの種類を知っているget_target以内に次のコード

template<typename T> 
struct id { typedef T type; }; 

template<typename T> 
id<T> make_id(T) { return id<T>(); } 

struct any_type { 
    template<typename T> 
    operator id<T>() const { return id<T>(); } 
}; 

template<typename T, typename Fn> 
T *get_target(boost::function<Fn> &f, id<T>) 
{ return f.template target<T>(); } 

void f(int a, int b) { std::cout << a << " " << b << std::endl; } 

int main() { 
    boost::function<void(int)> g = boost::bind(&f, _1, 10); 
    (*get_target(g, true ? any_type() : make_id(boost::bind(&f, _1, 10))))(2); 
} 

を検討できるようにするには。これを使用してtarget呼び出しを呼び出し、boost::functionの中にラップされたオブジェクトを返すことができます。 mainの中で、次にバインド式を呼び出します。このコードスニペットの仕組みを見るには、Eric Nieblerの記事Conditional Loveを読んでください。

+0

これについて適切な方法は何ですか?私はftwのコールバック関数として関数を使用したいと思いますが、コールバックと結果を入れるデータ構造体へのポインタも渡したいと思います.Boost.Bindはこのような問題を解決できるはずですそれについてどうすればいいですか? – HazyBlueDot

+0

'ftw'をテンプレートにしてみませんか?それから、 'boost :: bind'を介して関数ポインタから' boost :: function'への何かを受け入れることができます。それをテンプレートにしたくないのであれば、なぜパラメータ型として 'boos :: function'を使うのでしょうか?それはそれのためのものです:) –

+0

私は詳細を与える必要があります。 ftwは共有ライブラリの関数です(linux.die.net/man/3/ftwのman ftwを参照してください)、私はそのパラメータリストを制御しません。 – HazyBlueDot

1

他の回答は、コードが機能しない理由を示しています。ここでは、特定の限られた状況のために、ある種のことが起こる、本当に醜い解決策があります。

typedef int (*ftwpt)(const char*, const struct stat*, int); 
typedef boost::function<int(const char*, const struct stat*, int)> MyFTWFunction; 

template <MyFTWFunction *callback> 
class callback_binder { 
public: 
    static int callbackThunk(const char *s, const struct stat *st, int i) { 
     return (*callback)(s, i); 
    } 
}; 

extern void register_callback(callback_t f); 

int random_func(const char *s, const struct stat *st, int i) 
{ 
    if (s && *s) { 
     return i; 
    } else { 
     return -1; 
    } 
} 

MyFTWFunction myfunc; 

int main(int argc, const char *argv[]) 
{ 
    myfunc = random_func; 
    register_callback(&callback_binder<&myfunc>::callbackThunk); 
    return 0; 
} 

ポインタをテンプレート引数として使用するためのルールでは、引数として渡されるポインタがグローバル変数へのポインタである必要があります。もちろん、そのグローバル変数は匿名の名前空間で宣言することもできます。

醜いです。myMapの複数の可能なインスタンスを同時に呼び出したい場合は、可能な限り多くのグローバルMyFTWFunction変数をmyMapの同時インスタンスとして使用する必要があります。主に、グローバル変数の内容を使用して不足しているパラメータを埋めるサンク関数の作成を自動化します。ここで

はここで何が起こっているか、それがより明白にすることがあり、この狭い場合のために、ほぼ同じことをしLOTあまり柔軟性のあるバージョンである:あなたがmyMap_binder見ることができるように

#include <map> 
#include <string> 

using ::std::map; 
using ::std::string; 
typedef map<string, double*> myMap; 
typedef int (*callback_t)(const char *, struct stat *st, int); 

int myFunction(const char*, struct stat *st, int, myMap*); 

template <myMap **map_ptr> 
class myMap_binder { 
public: 
    static int call_my_function(const char *s, struct stat *st, int i) { 
     return myFunction(s, st, i, *map_ptr); 
    } 
}; 

extern void register_callback(callback_t f); 

myMap *mainmap; 
myMap *othermap; 

int main(int argc, const char *argv[]) 
{ 
    myMap m_map; 
    myMap m_map2; 
    mainmap = &m_map; 
    othermap = &m_map2; 
    register_callback(&myMap_binder<&mainmap>::call_my_function); 
    register_callback(&myMap_binder<&othermap>::call_my_function); 
    return 0; 
} 

テンプレートですグローバル変数の内容に含まれるサンク関数をコールバック関数の呼び出しに自動生成します。

0

これは数年遅れていますが、将来的にお手伝いしてくれるかもしれません。私の問題はわずかに異なりましたが、ソリューションから必要な答えを得ることができます。他の質問に
>Messaging system: Callbacks can be anything

関連する問題