8

So I have some code written before C++11 that parses a string based on template arguments. Instead of having one definition for each number of arguments I would like to use variadic templates, but I can't wrap my head around how to initialize a tuple correctly. See this simplified code of what I want, this is for the special case of 2 arguments:

template <typename Arg1, typename Arg2>
struct parser
{
  static tuple<Arg1, Arg2> parse(const string& str) 
  {
    Arg1 arg1;
    Arg2 arg2;
    // do the parsing with for example stringstream
    return tuple<Arg1, Arg2>(arg1, arg2);             
  }
};

I'm having problem with putting the arguments in the tuple in the variadic case. I can construct the return value holder with:

tuple<Args...> retVal; 

but I don't know if there is a way to iterate through the arguments and put them in a tuple. I've seen some recursive magic to get for example the printf functions, but I don't know if it could apply to this case.

Melebius
  • 6,183
  • 4
  • 39
  • 52
Rolle
  • 2,900
  • 5
  • 36
  • 40
  • Are you trying to change type of your tuple based on what came out of string parsing? – cababunga Apr 04 '12 at 16:05
  • 1
    It is possible to go over all the elements of a tuple without using recursion, but at the cost of an additional function call. I've described the technique several times ([here](http://stackoverflow.com/questions/9730593/how-can-i-call-a-set-of-variadic-base-class-constructors-based-on-tagged-argumen/9731981#9731981), [here](http://stackoverflow.com/questions/7381805/c-c11-switch-statement-for-variadic-templates/7383493#7383493), and [here](http://stackoverflow.com/questions/7089284/dynamic-dispatching-of-template-functions/7089649#7089649)). (The important bits being `indices` in each case.) – Luc Danton Apr 04 '12 at 16:27

1 Answers1

27

You don't need a helper class. Do it with functions instead.

template <typename T> std::tuple<T> parse(std::istream& is) 
{
  T t; is >> t;
  return std::tuple<T>(std::move(t));
}

template <typename T, typename Arg, typename... Args>
std::tuple<T, Arg, Args...> parse(std::istream& is) 
{
  T t; is >> t;
  return std::tuple_cat(std::tuple<T>(std::move(t)),
                        parse<Arg, Args...>(is));
}

template <typename... Args>
std::tuple<Args...> parse(const std::string& str) 
{
  std::istringstream is(str);
  return parse<Args...>(is);
}

EDIT: Today, I got the idea how to do it in a very simple way with the use of the expansion:

template <typename T> T read(std::istream& is)
{
  T t; is >> t; return t;
}

template <typename... Args>
std::tuple<Args...> parse(std::istream& is) 
{
  return std::make_tuple(read<Args>(is)...);
}

template <typename... Args>
std::tuple<Args...> parse(const std::string& str) 
{
  std::istringstream is(str);
  return parse<Args...>(is);
}
ipc
  • 8,045
  • 29
  • 33
  • thanx, i had no idea there was such a function as tuple_cat, great! – Rolle Apr 04 '12 at 19:27
  • @ipc It seems the order the streams are read is undefined if you use std::make_tuple(read(is)...). See http://stackoverflow.com/questions/14056000/how-to-avoid-undefined-execution-order-for-the-constructors-when-using-stdmake – Erik Sjölund Dec 30 '12 at 08:49
  • 1
    @ErikSjölund: AFAIR it is well defined (see § 8.5.4/4). – ipc Jan 02 '13 at 13:14
  • @ipc I guess I need buy the C++ standard to see that paragraph. In my question I was advised to use std::make_tuple {} instead of std::make_tuple() to avoid the stream from being read in an undefined order. But I just realized that your use of std::make_tuple is somewhat different from the one in my question. You have a function `read(is)` but I have a constructor `Args(is)`. So it's a bit different. – Erik Sjölund Jan 02 '13 at 18:57
  • 2
    @ErikSjölund: Buying the standard? [n3337](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) works just as fine. – ipc Jan 02 '13 at 20:21
  • The point is that `std::make_tuple(args(stream)...)` has indeed a defined order because of the `...`. I think that was at some time realized in your question (the even referred to § 8.5.4/4). – ipc Jan 02 '13 at 20:21
  • Thanks for providing the n3337 link! – Erik Sjölund Jan 02 '13 at 20:29
  • i am not sure what am i missing there but this parse function return empty tuple to me. https://onlinegdb.com/cXzGziwa7 – dixit_chandra Aug 30 '21 at 21:58