如何用模板参数或 std::function 替换函数指针?

How to replace a function pointer with a template parameter or a std::function?

我运行一个visualstudio中的sonarlint插件。 我的代码有一个主要问题,如下所示:

_declspec(dllexport) void GetInformation(void (add)(const char* pCarName))
{
    add("N3-988");
    add("N3-40");
    add("N3-41");
    add("N3-428");
}

错误是

cpp:S5205 : Replace this function pointer with a template parameter or a "std::function".

如何解决?

错误是转移注意力的错误。您打错了函数指针语法,仅此而已。你需要

void (*add)(const char* pCarName)

作为参数类型。 add那么就是一个函数指针,在函数体(add("N3-988");等)中的使用是合适的。

可能像下面这样

#include <cstdio>

template<typename FuncT>
void GetInformation(FuncT func)
{
    func("N3-988");
    func("N3-40");
    func("N3-41");
    func("N3-428");
}

int main()
{
    auto func = [](const char* s){ printf("%s\n",s); };

    GetInformation(func);
}

这不是真正的错误,从某种意义上说,您不能将函数指针用作参数。你可以。出于模糊性、灵活性和性能原因,不鼓励使用函数指针。请参见 https://jira.sonarsource.com/browse/RSPEC-5205。因此,如果您不关心这些注意事项,您可能想要抑制它。

缺乏灵活性意味着您无法传递额外的上下文(除非使用所谓的“thunks”)。可以通过为用户上下文使用额外的 void* 参数来解决这种缺乏灵活性的问题:

_declspec(dllexport) void GetInformation(
   void (add)(const char* pCarName, void* context), void* context)
{
    add("N3-988", context);
    add("N3-40",  context);
    add("N3-41",  context);
    add("N3-428", context);
}

您也可以按照建议使用 std::function,如果您不认为您的 DLL 将具有 C++ 接口(因此将取决于 C++ 运行时):

_declspec(dllexport) void GetInformation(std::function<void (const char*)> add)
{
    add("N3-988");
    add("N3-40");
    add("N3-41");
    add("N3-428");
}

请注意,您不能按照建议使用 template,因为无法使用 __declspec(dllexport) 从 DLL 导出模板。由于避免间接寻址,模板将具有固定性能,但 DLL 接口意味着您无法避免它。


注意函数作为参数:

void GetInformation(void (add)(const char* pCarName))

由于所谓的衰减:

相当于函数指针参数
void GetInformation(void (*add)(const char* pCarName))

建议用一个替换另一个的答案具有误导性,它不会解决任何问题。