codeinc
codeinc

Reputation: 59

why variadic template parameter packs not expanded?

#include<tuple>
#include<iostream>
using namespace std;

class A                                                                                                                                                           
{                                                                                                                                                                 
public:                                                                                                                                                           
  int v;                                                                                                                                                          
  A(int a) : v(a){}                                                                                                                                               
  operator int (){return v;}                                                                                                                                      
};                                                                                                                                                                

class B                                                                                                                                                           
{                                                                                                                                                                 
public:                                                                                                                                                           
  int v;                                                                                                                                                          
  B(int a) : v(a + 1) {}                                                                                                                                              
  operator int (){return v;}                                                                                                                                      
};                                                                                                                                                                

class C                                                                                                                                                           
{                                                                                                                                                                 
public:                                                                                                                                                           
  int v;                                                                                                                                                          
  C(int a) : v(a + 2){}                                                                                                                                               
  operator int (){return v;}                                                                                                                                      
};                                                                                                                                                                


template <typename... Args >                                                                                                                                      
int f(int a, Args... args )                                                                                                                                      
{                                                                                                                                                                 
  tuple<Args...> argstuple1( std::forward<Args>(a)... );                                                                                                          
  tuple<Args...> argstuple2(Args{a}...);                                                                                                                          
  //The following initialization won't compile
  tuple<Args...> argstuple2(Args(a)...);

  cout << (int)std::get<2>(argstuple2) << endl;                                                                                                                   
  return 1;                                                                                                                                                       
}  

int main()
{
  f< A, B, C>(5,0,0,0);
}

What I am trying to do here is, given one value, I have 3 different classes to handle this same value in 3 different ways. The problem I got here is how to expand the parameter packs and initialize each class with the given single value a.

tuple<Args...> argstuple2(Args(a)...);

I would think the above code would be expanded into

tuple<A, B, C> argstuple2(A(a), B(a), C(a));

Looks like the compiler doesn't like this. However, all following codes would just compile fine

tuple<Args...> argstuple2(Args(1)...);
tuple<Args...> argstuple2(Args{a}...);
tuple<Args...> argstuple2(std::forward<Args>(a)...);                  

I would like to know why Args(a)... fails to expand? What is the difference between Args(a)... and Args{a}...? How about std::forward(a)...)?

I am using gnu 4.7.1

Upvotes: 4

Views: 1310

Answers (2)

Kobi
Kobi

Reputation: 878

clang has a better error code:

<source>:36:28: warning: parentheses were disambiguated as a function 
declaration [-Wvexing-parse]
   tuple<Args...> argstuple3(Args(a)...);
                            ^~~~~~~~~~~~
<source>:36:29: note: add a pair of parentheses to declare a variable
   tuple<Args...> argstuple3(Args(a)...);
                            ^
                            (      )

vexing-parse should sound familiar. It is seen as a function declaration.

This argstuple3 looks like a function name, that returns a tuple<> and has arguments Args(a).

This Args(a) is seen as function pointer that returns 'Args' (type) and being passed 'a'

Compiler will see it as something like this

tuple<int> argtuple3(int());

If you give it a try, you'll see the same exact error.

Another option to solve this:

tuple<Args...> argstuple3{Args(a)...};

Upvotes: -1

Richard Hodges
Richard Hodges

Reputation: 69912

// now it will
using tuple_args = tuple< Args... >;                                                                                                                                                                 
tuple_args argstuple3((Args(a))...);

Upvotes: 3

Related Questions