[英]Initializer list, parameter pack expansion, fold expressions and order of evaluation
我有以下代码来处理 n 维张量 class (偏移量是 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];
}
这可行,但我有一些问题,因为我通过拼凑我在网上找到的大量信息编写了这段代码。
第一个是第 5 行发生的事情以及它的正确名称。 如果我没记错的话,这应该解压表达式并创建一个支撑初始化列表 [*]。 这个列表的每个元素本身就是一个逗号分隔的列表,格式为 (exp,0)[**]。 因此展开应该是 {(exp1,0),...(expn,0)}。 我对吗?
第二个是关于评估顺序。 [**] 应该只用于为 inizialier_list 的构造函数提供返回值而不用于其他目的(即使 index 本身可能是返回值?)。 [*] 相反,给出了表达式求值的顺序。 我在打印 function 的示例中找到了它:
(void)std::initializer_list<int>{(print(others),0)...};
以便在参数上按顺序调用 print。 这对于组合表达式也是如此吗?:
(void)std::initializer_list<int>{(print(compute(others)),0)...};
因此,如果“计算”取决于 state,则会根据导致始终相同结果的参数顺序进行更新(独立于编译器 ecc ...)。 在张量示例中,这指的是 ++i。
1. 你的理解是正确的。
2.我不确定“组合表达式”等是什么意思,但是是的,大括号中的初始化程序总是从左到右进行评估。 请参阅cppreference :
- 在列表初始化中,给定初始值设定项子句的每个值计算和副作用都在每个值计算和与任何初始值项子句相关联的副作用之前进行排序,在括号括起来的逗号分隔的初始值设定项列表中。
3. 这不是折叠表达式。 折叠表达式必须具有以下 forms 之一:
( pack op... )
(... op pack )
( pack op... op init )
( init op... op pack )
其中op
是二元运算符(大多数是允许的), pack
是一个表达式,包含至少一个未扩展的参数包(在您的情况下是Ts
或others
), init
只是一个普通表达式,并且...
必须按字面意思存在。
您的 function 可以使用折叠表达式进行简化。 代替:
(void)std::initializer_list<int>{(index += _offset[++i]*static_cast<std::size_t>(others), 0)...};
你可以写:
((index += _offset[++i]*static_cast<std::size_t>(others)), ...);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.