将通用函数分配给函数指针结构成员

时间:2021-02-21 19:31:40

标签: c++ generics function-pointers member-function-pointers

我必须分配结构的以下成员:

esp_err_t (*handler)(httpd_req_t *r);

如你所见,它是一个函数指针。我有一个 generic 模板函数,我想将其分配为 handler:

template <class Tmsg>
esp_err_t HandleRpc(httpd_req_t *req){...}

我在 generic 模板类中分配了 handler 成员,所以我有一个泛型类型参数 Tpayload

httpd_uri_t cfg = {
    ...
    .handler = HandleRpc<Tpayload>,
    ...
};

我明白了:

<块引用>

'>' 标记前的预期主表达式

问题在于我不能传递成员方法指针(IE esp_err_t (RpcServer::*)(...)),但 RpcServer 是一个 generic 模板类(IE 有一个带有一个泛型参数的模板)。所以我认为通过创建一个 generic 模板函数 outisde 类(全局范围?),并将 RpcServer 实例传递给该函数,我将能够检索我的 RpcServer<T> 实例,一切都会好起来的。

这是我能想出的最少代码来重现问题:

int main()
{
    
}

template <class T>
class RpcServer{
    public:
        void RegisterHandler();
};

struct HandlerInfo{
    void (*handler)();
};

template <class T>
void Handle(RpcServer<T> test)
{

}

template <class T>
void RpcServer<T>::RegisterHandler(){
    HandlerInfo info = {
        .handler = Handle<T>;
    };
}

我是否错过了显而易见的事情,或者我正在尝试做的事情需要一些更丑陋的技巧?

1 个答案:

答案 0 :(得分:0)

struct HandlerInfo{
    void (*handler)();
};

handler 是指向不带参数且不返回任何内容的函数的指针。您可以将此指针设置为指向任何函数。只要它不带参数,不返回任何东西(它的返回类型是void)。没有例外,这就是 C++ 的工作方式,它是一种强类型语言。

template <class T>
void Handle(RpcServer<T> test)
{

这是一个接受一个参数的函数的模板。参数的类型并不重要。关键是这个模板的每个实例都是一个函数,它总是只接受一个参数。

在 C++ 中,指向没有参数的函数的指针只能设置为指向这样的函数。您不能将此函数指针设置为指向带有一个参数、两个参数或十个参数的函数。它只能设置为一个参数正好为零的函数。那是因为那是指针指向的东西。

如果您要更改模板函数使其不带参数,那么当然可以:

int main()
{

}

template <class T>
class RpcServer{
    public:
        void RegisterHandler();
};

struct HandlerInfo{
    void (*handler)();
};

template <class T>
void Handle()
{

}

template <class T>
void RpcServer<T>::RegisterHandler(){
    HandlerInfo info = {
            .handler = Handle<T>
    };
}

这是在 gcc 10 上编译的。“.member”初始化语法已经被 gcc 支持很长时间了,但它只是从 C++20 开始标准化,所以其他编译器可能不支持这种语法。

如果您愿意,您可以将其声明为指向以 RpcServer<int> 作为其参数的函数的指针:

struct HandlerInfo{
    void (*handler)(RpcServer<int>);
};

现在,您将能够初始化它以指向这样的函数:

HandlerInfo info = {
    .handler = Handle<int>
};

HandleInt 实例化一个接受此类参数的函数,因此类型完全匹配。

或者,使 HandlerInfo 本身成为匹配模板:

template <class T>
class RpcServer{
    public:
        void RegisterHandler();
};

template<class T>
struct HandlerInfo{
    void (*handler)(RpcServer<T>);
};

template <class T>
void Handle(RpcServer<T> )
{

}

template <class T>
void RpcServer<T>::RegisterHandler(){
    HandlerInfo<T> info = {
        .handler = Handle<T>
    };
}

int main()
{
    RpcServer<int> server;

    server.RegisterHandler();
}

(注意——你的代码有其他语法错误;如果它们被修复,一开始看起来代码会编译;但是如果尝试实例化模板,它会因为类型不匹配而失败)