1

In the following snippet:

void normalize(path& p)
{
   // do something with p
}

template<typename... T>
void normalize(T&... t)
{
     normalize(t)...;  // (L)
}

In my actual understanding, the line (L) expands to:

template<typename... T>
void normalize(T&... t)  // T = {t1, t2, t3}, for example
{
    normalize(t1), normalize(t2), normalize(t3);
}

and each one of these expressions will execute the one-parameter version of normalize. However, g++ (4.8.1) throws me the following error:

prueba.cpp: In function 'void normalize(T& ...)':
prueba.cpp:155:17: error: expected ';' before '...' token
     normalize(t)...;
             ^
prueba.cpp:155:20: error: parameter packs not expanded with '...':
     normalize(t)...;
                    ^
prueba.cpp:155:20: note:         't'

What's wrong with my code?

Constructor
  • 7,273
  • 2
  • 24
  • 66
ABu
  • 10,423
  • 6
  • 52
  • 103

2 Answers2

4

The expansion of parameter packs is not allowed in this context. If you create a helper class pass, you can do the following:

pass{(normalize(std::forward<T>(t)), 0)...};

The helper class pass might look as follows:

struct pass
{
    template <typename ...Args>
    explicit pass(Args&&...) { }
};
nosid
  • 48,932
  • 13
  • 112
  • 139
  • I don't understand why it's neccessary the ", 0" expression – ABu May 25 '14 at 21:17
  • 1
    @Peregring-lk: The return type of `normalize` is `void`, but you can't pass `void` as arguments to a function/constructor. For that reason, I use the comma operator to evaluate the expressions, and get dummy values as arguments. – nosid May 25 '14 at 21:22
  • I've just realized it before reading your comment. Thanks anyway for confirming my suspicions! – ABu May 25 '14 at 21:25
  • Last thing, the use of `{}` instead of `()` is only for avoiding unsequenced evaluation, right? – ABu May 25 '14 at 21:26
  • 1
    With `{}` the _initializer-clauses_ are evaluated in the order in which they appear. Unfortunately, GCC up to 4.9 is still broken in this regard. Regardless, I prefer `{}` because it avoids the _most vexing parse problem_. – nosid May 25 '14 at 21:48
  • 1
    You can also try: `[](...){}(normalize(std::forward(t)), 0)...);`. The anonymous lambda with unspecified arguments `[](...){}` seems to be able to provide the necessary expansion context without defining `pass`. – liori Aug 30 '14 at 20:31
0

I think you would want to unpack your parameter pack into a function call site or tuple, like this:

  make_tuple(normalize(t)...);  // (L)

For example, the following code would compile under gcc-4.8.1:

#include <tuple>
using namespace std;
typedef  int path;
void normalize(path& p)
{
   // do something with p
}

template<typename... T>
void normalize(T&... t)
{
  auto tp = make_tuple(normalize(t)...);  // (L)
  //do whatever you want with the components of tp ...
}

main() {}
thor
  • 21,418
  • 31
  • 87
  • 173
  • yes, it's an old c/c++ syntax that still compiles with g++ 4.8.1. Didn't want the noise so used the minimum. – thor May 26 '14 at 19:22