0

C libstrophe ライブラリを使用して、C++11 で xmpp アプリケーションを作成しています。特定の ID のメッセージ ハンドラーを登録しようとしているので、xmpp_id_handler_addを使用して特定の戻りメッセージを認識できます。

void xmpp_id_handler_add(xmpp_conn_t * const conn,
                         xmpp_handler handler,
                         const char * const id,
                         void * const userdata)

しかし、私が理解していないこれのstropheの実装について何かがあります.

Strophe は、次の形式の関数ポインターのみを受け入れます。

typedef int (*xmpp_handler)(xmpp_conn_t * const conn, 
                            xmpp_stanza_t * const stanza, 
                            void * const userdata);

静的関数を使用するのは簡単ですが、ソースコードを調べると、これが見つかります

    /* check if handler is already in the list */
    item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
    while (item) {
        if (item->handler == (void *)handler)
            break;
        item = item->next;
    }
    if (item) return;

つまり、同じ静的関数で xmpp_id_handler_add を 2 回呼び出そうとすると、ID とユーザーデータが異なると、2 回目の呼び出しが拒否されます。

そのため、新しい ID ハンドラーを追加するたびにラムダを作成できるのではないかと考えました。

auto msgHandler = [](xmpp_conn_t* const pConn, 
                     xmpp_stanza_t* const pStanza, 
                     void* const pUserdata) -> int

しかし、ラムダのポインター値を見たとき

printf("%p\n", (void*)((xmpp_handler)msgHandler));

2回実行したところ、両方とも同じ値が得られました。この場合、ラムダは静的関数のようです。

では、新しい ID をリッスンするたびに、新しい一意の関数ポインターを作成するにはどうすればよいでしょうか? あるいは、libstrophe の使用方法を誤解していますか? リッスンする新しい ID ごとに新しい静的関数を用意する必要がありますか?

4

3 に答える 3

1

libstrophe イシュー トラッカー ( https://github.com/strophe/libstrophe/issues/97 ) で同じ問題が既に言及されています。分離されたブランチには、マスター ブランチにマージされるパッチがあります。したがって、マイナー リリース0.9.2にはそれが含まれます。このパッチにより、 だけではなくhandlerプラスの一意のペアを追加できます。userdatahandler

于 2016-12-16T00:03:53.767 に答える
1

c++11 の場合、ラムダをインラインで宣言できるようにするのは簡単ではありませんが、試してみましょう。ラムダをラップするヘルパー構造体を作成することもできますが、単項演算+子が constexpr ではない (ラムダにはリンケージがない) ため、いくつかの回避策を実行する必要があります...:

template <class... Args>
struct voider {
    using type = void;
};

template <std::size_t, class, class = void>
struct FunctionWrapper;

template <std::size_t N, class L>
struct FunctionWrapper<N, L, typename voider<decltype(&L::operator())>::type>: FunctionWrapper<N, decltype(&L::operator())> {};

template <std::size_t N, class Res, class L, class... Args>
struct FunctionWrapper<N, Res (L::*)(Args...) const, void> {
    static Res (*l)(Args...);
    static Res foo(Args... args) {
        return l(args...);
    }
};

template <std::size_t N, class Res, class L, class... Args>
Res (* FunctionWrapper<N, Res (L::*)(Args...) const, void>::l)(Args...);

FunctionWrapperstd::size_t各ペアxに一意の静的関数を提供する必要がありますLambda。実際のラッピングを行う関数:

template <std::size_t N, class L>
decltype(&FunctionWrapper<N, L>::foo) wrap(L &l) {
    FunctionWrapper<N, L>::l = +l;
    return &FunctionWrapper<N, L>::foo;
}

wrapまた、各呼び出しのコンパイル時に既知の値として一意の ID を提供する限り、渡されたラムダの一意の関数ポインターを楽しむことができます。

auto lambda = [](int x){std::cout << x << std::endl;};
std::cout << (void *)wrap<0>(lambda) << std::endl;
std::cout << (void *)wrap<1>(lambda) << std::endl;
wrap<0>(lambda)(1);
wrap<1>(lambda)(1);

出力例:

0x400f28
0x400f76
1
1

【ライブデモ】

于 2016-12-15T16:23:58.710 に答える