【问题标题】:Initializer list, parameter pack expansion, fold expressions and order of evaluation初始化列表、参数包扩展、折叠表达式和求值顺序
【发布时间】:2020-11-29 05:37:37
【问题描述】:

我有以下代码来处理 n 维张量类(偏移量是 std::size_t 的 std::vector):

template <typename ...Ts>
double Tensor::at(int first, Ts... others) {
    int i = 0;
    std::size_t index = static_cast<std::size_t>(first)*_offset[0];
    (void)std::initializer_list<int>{(index += _offset[++i]*static_cast<std::size_t>(others), 0)...};
    return _data[index];
}

这可行,但我有一些问题,因为我通过拼凑我在网上找到的大量信息编写了这段代码。

  1. 第一个是第 5 行发生的事情以及它的正确名称。如果我没记错的话,这应该解压表达式并创建一个支撑初始化列表 [*]。这个列表的每个元素本身就是一个逗号分隔的列表,格式为 (exp,0)[**]。因此展开应该是 {(exp1,0),...(expn,0)}。我说的对吗?

  2. 第二个是关于评估顺序的。 [**] 应该只用于为 inizialier_list 的构造函数提供返回值而不用于其他目的(即使 index 本身可能是返回值?)。 [*] 相反,给出了表达式求值的顺序。我在打印函数的示例中找到了它:

(void)std::initializer_list<int>{(print(others),0)...}; 

以便在参数上按顺序调用 print。这对于组合表达式也是如此吗?:

(void)std::initializer_list<int>{(print(compute(others)),0)...}; 

因此,如果“计算”取决于状态,则会根据导致始终相同结果的参数顺序进行更新(独立于编译器 ecc...)。在张量示例中,这指的是 ++i。

  1. 最后一个问题指的是this,其中使用+= 的方式来处理张量被称为折叠表达式。我认为情况并非如此。我错了吗?

【问题讨论】:

    标签: c++ c++17 initializer-list fold-expression parameter-pack


    【解决方案1】:

    1。你的理解是正确的。

    2。我不确定您所说的“组合表达式”等是什么意思,但是是的,大括号中的初始化程序总是从左到右进行评估。见cppreference

    1. 在列表初始化中,给定初始化器子句的每个值计算和副作用都排在与任何初始化器子句相关联的每个值计算和副作用之前,这些初始化器子句在初始化器的大括号括起来的逗号分隔列表中。李>

    3。这不是折叠表达式。 fold expressions 必须具有以下形式之一:

    • ( pack op ... )
    • ( ... op pack )
    • ( pack op ... op init )
    • ( init op ... op pack )

    op 是一个二元运算符(大多数是允许的),pack 是一个包含至少一个未扩展参数包的表达式(Tsothers 在您的情况下),init 只是一个普通的表达式,... 必须是字面意思。

    您的函数可以使用折叠表达式进行简化。而不是:

    (void)std::initializer_list<int>{(index += _offset[++i]*static_cast<std::size_t>(others), 0)...};
    

    你可以写:

    ((index += _offset[++i]*static_cast<std::size_t>(others)), ...);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-13
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 2022-01-19
      • 1970-01-01
      • 2019-12-25
      • 1970-01-01
      相关资源
      最近更新 更多