0

I'm trying to store a list of user commands in a struct. The struct consists of a command (char array) and a pointer to a static member function which may have any number of arguments. I would like to be able to instantiate the struct, and store them in a vector, and then when accessing one, to call the function pointer it stores, passing in the necessary arguments.

After a lot of reading and experimenting this is what I've come up with:

template<typename F, F func, typename... Args>
struct InputCommand
{
public:
    char input[ 32 ];
    void ( Interpreter::*func )( Args... args );

    InputCommand( const char input[] )
    {
        strcpy( this->input, input );
    }
};

The above seems reasonably logical to me, however I get an error when trying to declare my vector of type InputCommand:

vector<InputCommand> m_commandList;

InputCommand<void *, cmdAddState, const char, const char> command( "addstate" );
m_commandList.push_back( command );

According to the compiler the declaration needs a command list but I'm really not sure what to do. FYI the function cmdAddState is as follows:

static void Interpreter::cmdAddState( const char, const char );

Any help would be very much appreciated. Thank you!

Amir Kirsh
  • 12,564
  • 41
  • 74
T. Elliott
  • 31
  • 5
  • Why do you need this? Can't you use `std::function`? – user0042 Oct 08 '17 at 09:01
  • please post a [mcve] – m.s. Oct 08 '17 at 09:11
  • How do you plan to call `func`? How are you going to turn `input` into a list of arbitrary arguments of arbitrary types? – Igor Tandetnik Oct 08 '17 at 14:24
  • 1
    @IgorTandetnik _input_ only stores the name of the command. The values of the arguments are read somewhere else - the vector will be searched to find the matching command by _input_, and then I would execute the function from the pointer stored in the found object, and passing in the arguments. The idea here is to have all these predefined possible user commands. If there some other way to do this I'd be glad try it - however I'd like it to be more sophisticated then using multiple if-else statements and calling the function directly. – T. Elliott Oct 09 '17 at 04:40
  • Possible duplicate of [Store functions with different signatures in a map](https://stackoverflow.com/questions/45715219/store-functions-with-different-signatures-in-a-map) – Caleth Oct 09 '17 at 08:30
  • Suppose you managed to have a map of `string` to "something" that represents all the various functions. Then the calling code retrieves "something" from the map and tries to call it - how would *that* code know which arguments to pass and where to get them? I assume commands don't all have the same signature; because if they do, then that's straightforward. – Igor Tandetnik Oct 09 '17 at 13:37

1 Answers1

0

The problem is with trying to hold a vector of generic types:

vector<InputCommand> m_commandList;

Since InputCommand is a template, the vector needs to know which exact type of InputCommand would be stored.

Similarly you cannot have a vector of vectors without defining the type of the inner vector:

vector<vector> cant_do;

But you can of course do:

vector<vector<int>> fine;

So if you would state the template parameters for the InputCommand in your vector<InputCommand> this would compile.

However, you want to store any kind of InputCommand (same as if we want to store in a vector 'all sorts of vectors', not necessarily vector of ints).

This can be achieved by having a base class to your InputCommand template class (e.g. AbstractInputCommand) and having the vector hold pointers to this base class, allowing holding derived pointers. But when you come to call the actual stored function you would have a problem as the different number of arguments doesn't allow to declare a virtual method at the base.

And of course there is also the option of using std::function. But using std::function is not enough to allow holding different types of std::function.


At the end this comes to the problem that in C++ unfortunately template methods, like: template<typename... Args> void call() cannot be virtual. Which makes it hard to have a simple call to the actual function that you store.


A possible solution to your problem can be found here:

Storing and calling functions of different arguments in one function container

See also:

Container for pointers to member functions with different arguments

Amir Kirsh
  • 12,564
  • 41
  • 74