Search code examples
c++c++11initializationstd-functionpointer-to-member

Error in vector of struct with implemented Functions


I get the Erro:

"no instance of constructor "std::vector<_Ty, _Alloc>::vector 
 [with _Ty=FunctionToUpdate, _Alloc=std::allocator<FunctionToUpdate>]" matches the argument list" 

No matter how I change it, it persists, as long I keep it as a class. If I keep it all in just a simple .cpp without class and header, it all resolves easily. My.h:

#include <vector>
#include <functional>
#include <iostream>

struct Params
{
    std::vector<int> Integers;
    std::vector<std::string> Strings;
};

struct FunctionToUpdate
{
    int Version;
    std::function<void(int, Params)> Function;
    Params Parameters;
};

class Error
{
public:
    Error();
    void testFunctionA(int a, Params p);
    void testFunctionB(int a, Params p);
protected:
    const static std::vector<FunctionToUpdate> table;
};

Here is my .cpp, please assist me, I can't find the error:

#include "ErrorHandling.h"

Error::Error()
{
    for (auto functionToUpdate : table)
    {
        functionToUpdate.Function(functionToUpdate.Version, functionToUpdate.Parameters);
        std::cout << "############################################" << std::endl;
    }
    std::cout << "Done!" << std::endl;
}

void Error::testFunctionA(int a, Params parameter)
{
    //std::cout << "Size Integers: " << parameter.Integers.size() << std::endl;
    //std::cout << "Size Strings: " << parameter.Strings.size() << std::endl;

    std::cout << a << std::endl;

    for (auto& integer : parameter.Integers)
    {
        std::cout << integer << std::endl;
    }
    for (auto& integer : parameter.Strings)
    {
        std::cout << integer << std::endl;
    }
}

void Error::testFunctionB(int a, Params parameter)
{
    std::cout << a << std::endl;
    std::cout << parameter.Integers.at(0) << std::endl;
}

const std::vector<FunctionToUpdate> Error::table
{                                                       // <-- here the Error happens
    { 100, &testFunctionA, { {177}}},
    { 1948, &testFunctionB, { {314}}},
};

int main()
{
    Error error;
}

Solution

  • Your code has a few issues

    1. First, the correct initialization of static member Error::table would be as follows:

      const std::vector<FunctionToUpdate> Error::table
      {                                                  
          { 100, &Error::testFunctionA, { { {177} }, { {"string"} } }},
          { 1948, &Error::testFunctionB, { { {314} }, { {"string"} } } }
      };
      

      Note that the syntax &Error::testFunctionA for addressing the member function pointer. Additionally, the Params has two vectors. One is std::vector<int> and the other is std::vector<std::string>. In your code, the std::vector<std::string> has not been mentioned.

    1. In FunctionToUpdate the member function pointer type is wrong. Using typed member function pointer, you could

      // forward declaration
      class Error;
      // member function pointer type
      using ErrorFunType = void(Error::*)(int, Params);
      
      struct FunctionToUpdate
      {
          int Version;
          ErrorFunType Function;
          Params Parameters;
      };
      
    2. Secondly, the call to pointer to the member function in Error::Error() is wrong. It needs an (Error class) instance to call with. For example:

      for (auto functionToUpdate : table)
      {
         (this->*functionToUpdate.Function)(
            functionToUpdate.Version, functionToUpdate.Parameters
         );
         // or more generic `std::invoke` (since c++17)
         // std::invoke(functionToUpdate.Function
         //    , this, functionToUpdate.Version
         //    , functionToUpdate.Parameters);
         // ...
      }
      

    The above changes will make, your code compiles again!


    In case of wondering, how to handle the pointer to member function with std::function, (one way) to wrap the instance to call the member along with the std::function type.

    Following is the example:

    // forward declaration
    class Error;
    // member function pointer
    using ErrorFunType = std::function<void(Error*, int, Params)>;
    
    struct FunctionToUpdate
    {
        int Version;
        ErrorFunType Function;
        Params Parameters;
    };
    

    now in Error::Error()

    Error::Error()
    {
        for (auto functionToUpdate : table)
        {
            functionToUpdate.Function(this
                , functionToUpdate.Version, functionToUpdate.Parameters);
        }
    }
    

    See a demo