为什么可变参数模板参数包未展开

why variadic template parameter packs not expanded?

本文关键字:参数 包未展 变参 为什么      更新时间:2023-10-16
#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);
}

在这里要做的是,给定一个值,我有 3 个不同的类以 3 种不同的方式处理相同的值。我在这里遇到的问题是如何扩展参数包并使用给定的单个值 a 初始化每个类。

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

我认为上面的代码会扩展到

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

看起来编译器不喜欢这样。但是,以下所有代码都可以正常编译

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

我想知道为什么Args(a(...无法扩展?Args(a(之间有什么区别?和Args{a}...?std::forward(a(...(怎么样?

我正在使用 gnu 4.7.1

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

clang 有一个更好的错误代码:

<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)...);
                            ^
                            (      )

令人烦恼的解析应该听起来很熟悉。它被视为函数声明。

这个 argstuple3 看起来像一个函数名称,它返回一个元组<>并具有参数 Args(a(。

此 Args(a( 被视为返回"Args"(类型(并传递"a"的函数指针

编译器会将其视为这样

tuple<int> argtuple3(int());

如果您尝试一下,您将看到完全相同的错误。

解决此问题的另一种选择:

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