如何在C ++中创建唯一的lambda实例?或者,如何使用libstrophe在xmpp中设置id消息处理程序?

时间:2016-12-14 15:19:17

标签: c++ lambda libstrophe

我使用C libstrophe library在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只接受格式为

的函数指针
typedef int (*xmpp_handler)(xmpp_conn_t * const conn, 
                            xmpp_stanza_t * const stanza, 
                            void * const userdata);

使用静态函数很容易,但查看源代码我发现this

    /* 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两次,但使用不同的id和userdata,它将拒绝第二次调用。

所以我想也许每次我想添加一个新的ID处理程序时都可以创建一个lambda,就像这样

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

但是当我查看lambda的指针值

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

并且跑了两次,我两次得到相同的值。在这种情况下,lambda似乎就像一个静态函数。

那么,每次我想要收听新ID时,如何创建一个新的,唯一的函数指针?或者,我是否误解了如何使用libstrophe?你应该为你想听的每个新ID都有一个新的静态函数吗?

3 个答案:

答案 0 :(得分:1)

如果您正在使用c ++ 14,那么每次调用它时都可以创建一个通用lambda返回唯一的lambda(或者更确切地说lambda转换为静态函数):

uploadArchives {
    configuration = configurations.archives
    repositories.mavenDeployer {

        repository(url: constants.snapshotUrl) {
            authentication(userName: userName, password: password)
            pom.groupId = constants.groupId
            pom.artifactId = constants.libUIArtifactIdName
            pom.version = constants.projectVersion
        }

        pom.whenConfigured { pom ->
            pom.dependencies.forEach { dep ->
                if (dep.getVersion() == "unspecified") {
                    dep.setGroupId(constants.groupId)
                    dep.setVersion(constants.projectVersion)
                }
            }
        }

    }
}

并且每次使用不同的auto msgHandlerCreator = [](auto X){ return +[](xmpp_conn_t* const pConn, xmpp_stanza_t* const pStanza, void* const pUserdata) -> int {/*...*/}; }; 来调用它,例如:

std::integral_constant

答案 1 :(得分:1)

对于c ++ 11,允许将lambda声明为内联并不容易,但让我们试一试。我们可以创建一些辅助结构来包装我们的lambda,但是由于一元+运算符不是constexpr(lambda没有链接),我们需要做一些变通方法......:

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...);

FunctionWrapper现在应该为每对std::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;
}

我们可以享受传递lambda的唯一函数指针,只要我们在编译时为每个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

[live demo]

答案 2 :(得分:1)

libstrophe问题跟踪器中已经提到了同样的问题:https://github.com/strophe/libstrophe/issues/97。在分离的分支中有一个补丁,它将被合并到主分支。因此,次要版本0.9.2将包含它。该补丁允许添加handleruserdata的唯一对,而不仅仅是handler