将泛型函数分配给函数指针结构成员

Posted

技术标签:

【中文标题】将泛型函数分配给函数指针结构成员【英文标题】:Assign generic function to function pointer struct memeber 【发布时间】:2021-02-21 19:31:40 【问题描述】:

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

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

我明白了:

“>”标记之前的预期主表达式

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

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

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

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

【问题讨论】:

与您的要求无关,但仅供参考,这些在 C++ 中被称为模板。泛型不是 C++ 术语。 这不是“通用函数”。这是一个模板。模板不是离散函数,也不是离散类。在 Java 和 C# 中使用术语“泛型”,语法非常相似,但是 C++ 不是 Java 或 C#,并且以根本不同的方式工作。 C++ 模板什么都不是,就像 Java 或 C# 泛型一样。在这里了解 C++ 模板的基本工作原理很重要。在您的示例中,“HandleRpc”不是函数,因此不能有指向它的函数指针。 HandleRpc 是一个模板。 @SamVarshavchik C++ 中的 AFAIK 模板使编译器能够根据需要为尽可能多的类型参数“动态编写”函数或类。我知道它们与 C# 泛型不同,但我仍然不明白为什么这不起作用。 .handler = HandleRpc&lt;Tpayload&gt; 不会“创建”模板的“离散实例”吗? 为了理解“为什么这行不通”,您需要显示一个minimal reproducible example,任何其他人都可以剪切/粘贴完全如图所示 然后尝试编译并重现您的编译错误。显示的代码不完整,不足以确定这一点。注意:这并不意味着将整个程序发布到 ***,而只是重现编译错误所必需的最小值 也许 .handler = HandleRpc&lt;Tpayload&gt;, 应该是 .handler = HandleRpc&lt;Tpayload&gt;(), 以便模板构造对象或类? 【参考方案1】:
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 才被标准化,所以其他编译器可能不支持这种语法。

如果您愿意,可以将 this 声明为指向以 RpcServer&lt;int&gt; 作为参数的函数的指针:

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

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

【讨论】:

以上是关于将泛型函数分配给函数指针结构成员的主要内容,如果未能解决你的问题,请参考以下文章

将类的成员函数分配给 C++ 中的函数指针

泛型成员函数指针作为模板参数

Kotlin泛型 ① ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 )

将泛型 TArray 转换为 varArray

Kotlin 泛型中的 in 和 out

将泛型类型转换为具体类型时出错