mardi 26 septembre 2017

C++ Generic command parser with parameter pack expansion

I'm trying to write some sort of command handler, which can tokenize an istringstream, automatically convert the tokens into variables of specific types and call a callback function with the converted variables as arguments. Here is simplified version of my code:

void Callback(int x, char y, float z) {
  // do whatever
  // note: For simplicity, I use a callback with a fixed signature
  //       here. In my actual implementation, the callback can be
  //       called with any number and types of arguments - but that
  //       I have solved already.
}

template<typename T>
T GetNextArgument(std::istringstream& strm) {
  // get one token from the input stream and convert it to the required type
  T val;
  strm >> val;
  return val;
}

template<typename ...Args>
void ParseAndExecute(std::istringstream& input_stream) {
  Callback(GetNextArgument<Args>(input_stream)...);
}

int main() {
  std::istringstream strm("15 a 17.3");
  ParseAndExecute(strm);
  return 0;
}

The problem I have is that the ParseAndExecute() function after parameter pack expansion looks like this:

void ParseAndExecute(std::istringstream& strm) {
  Callback(GetNextArgument<int>(strm), 
           GetNextArgument<char>(strm),
           GetNextArgument<float>(strm));
}

Since the order of evaluation of the arguments is not defined, the tokens may be taken from the stream in incorrect order (and in my case, they always are). Instead I would need the expansion to give me something more like that:

void ParseAndExecute(std::istringstream& strm) {
  int a1 = GetNextArgument<int>(strm);
  char a2 = GetNextArgument<char>(strm);
  float a3 = GetNextArgument<float>(strm);
  Callback(a1, a2, a3);
}

But I cannot see how to achieve that with parameter pack expansion. Maybe with a recursive template...? Or do you have any other suggestion to achieve a similar functionality?

Aucun commentaire:

Enregistrer un commentaire