Search code examples
c++sonarlint

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


I run a sonarlint plugin in visualstudio. I get a major problem about my code as below :

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

The error is

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

How to fix it ?


Solution

  • It is not a real error, in a sense that you cannot use function pointer as a parameter. You can. Use of function pointers is discouraged for obscurity, flexibility and performance reasons. See https://jira.sonarsource.com/browse/RSPEC-5205 . So you may want to suppress it, if you are not concerned with these considerations.

    Lack of flexibility means you cannot pass extra context (unless using so called "thunks"). This lack of flexibility can be addressed by using extra void* parameter for user context:

    _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);
    }
    

    You can also used std::function, as suggested, if you don't ming that your DLL will have C++ interface (so will depend on C++ runtime):

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

    Note that you cannot use template as suggested, since templates cannot be exported from DLL with __declspec(dllexport). Template would have fixed performance due to avoiding indirections, but DLL interface means you can't avoid it.


    Note that function as a parameter:

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

    equivalent to function pointer parameter due to so called decay:

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

    The answer that suggest to replace one with the other is misleading, it wouldn't fix anything.