【问题标题】:Parameter packs not expanded with '...'未使用“...”扩展的参数包
【发布时间】:2015-11-23 10:17:35
【问题描述】:

我有这个代码:

#include <iostream>
using namespace std;

int print(int i)
{
    cout << endl << i;
}

template<typename ...Args>
inline void pass(Args&&...args)
{

}

template<typename ...args>
inline void expand(args&&... a)
{
    print(a) ...; //this doesn't expand
    //pass( print(a)... ); this works
}

int main() {
    expand(1,2,3,4);
    return 0;
}

它会抛出一个错误:

 In function 'void expand(args&& ...)':
error: expected ';' before '...' token
  print(a) ...;
           ^
parameter packs not expanded with '...':
  print(a) ...;
              ^

为什么需要使用pass() 函数?

【问题讨论】:

  • 在允许逗号分隔列表的情况下,基本上允许参数包扩展。有固定数量的上下文:函数参数列表、模板参数列表、初始化器等。表达式不是有效的上下文。逗号运算符不会生成逗号分隔的列表。

标签: c++ c++14 variadic-templates variadic-functions


【解决方案1】:

本质上,扩展参数包E... 会为包中的每个元素生成一个列表 E1, E2, [...], EN,一个E。这种语法结构仅在列表语法正确的地方有效,例如在函数调用、初始化列表等中。包含多个逗号运算符的表达式不计算在内。

我相信使用fold expressions (N4295: Folding expressions (Andrew Sutton, Richard Smith)) 你可以简单地写:

(print(a), ...);

在这个表达式中,

  • print(a) 是一个带有未扩展参数包的表达式,
  • , 是运营商,
  • ... 指定右折叠展开。

整个表达式的结果是(print(a), ...)会变成

print(a1) , (print(a2), (print(a3), print(a4))) // (assuming four elements). 

【讨论】:

  • 现在你让我想知道为什么会这样,因为foo(), foo(); 是一个有效的表达式。
  • @RichardHodges 这是一个有效的表达式,但根据语法它不是一个 列表
  • 我明白这一点。我想知道的是为什么包扩展仅限于列表并且不允许用于语句。
  • @RichardHodges 老实说,我不确定。我认为当我们得到折叠表达式时,这一切都会得到解决。
  • 你是对的。我使用-std=c++1z 尝试了apple clang。按预期工作。
【解决方案2】:

包扩展只能在包扩展上下文中发生。这些基本上是:

  • 支撑初始化
  • 初始化列表
  • 聚合初始化
  • 函数调用
  • 数组初始化

在您的情况下,这些更容易使用的是最后一个:

#include <iostream>
using namespace std;
int print(int i)
{
    cout<<endl<<i;
    return 0;
}

template<typename ...args>
inline void expand(args&&... a)
{
    using expander = int[]; 
    (void)expander{0, ((void)print(a), 0)...}; 
}

int main() 
{
    expand(1,2,3,4);

    return 0;
}

Demo

【讨论】:

  • @LightnessRacesinOrbit 我不明白
  • 我在嘲笑 C++。这种语法是做这个简单事情的“最简单”的方法,这很可笑。
【解决方案3】:

这个也可以:

#include <iostream>

void print() {}

template<typename T, typename ... Types>
void print (T firstArg, Types ... args) {
    std::cout << firstArg << "\n";
    print(args...);
}

int main() {
    print("Hello",1337,42.44,"World");
}

Demo

【讨论】:

    【解决方案4】:

    加上C++17和折叠表达式,上面的代码可以简化如下:

    #include <iostream>
    
    template<typename ...args>
    inline void print(args&&... a) {
        ((std::cout << a << std::endl), ...);
    }
    
    int main() {
        print(1,2,3,4);
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      您可能需要考虑以下 C++ 11 代码:

      #include <iostream>
      
      template<typename T, typename... Ts>
      auto printf3(T value, Ts... args) {
          std::cout << value << std::endl;
          (void) std::initializer_list<T>{([&args] {
              std::cout << args << std::endl;
          }(), value)...};
      }
      

      【讨论】:

        猜你喜欢
        • 2018-03-28
        • 1970-01-01
        • 2012-09-12
        • 2011-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多