考虑以下MCVE,其中我有两个值数组,其中w
是v
(try it out here)的两倍:
#include <valarray>
using namespace std;
int main() {
valarray<int> v { 1, 2, 3 };
for ([[maybe_unused]] auto x : v) {} // Ok
auto w = v * 2; // Leads to failure in loop below
//valarray<int> w = v * 2; // Works
//auto w = v*=2; // Works
//auto w = v; w *= 2; // Works
for ([[maybe_unused]] auto x : w) {} // Failure here
}
此示例无法在最后一个循环中使用clang和gcc编译(此处为gcc输出):
error: no matching function for call to 'begin(std::_Expr<std::__detail::_BinClos<std::__multiplies, std::_ValArray, std::_Constant, int, int>, int>&)'
问题的根源似乎是v * 2
的递减类型(我认为因为显式地记录了该类型是可行的,所以似乎正在进行一些隐式转换)。
看着reference notes,看来operator*
可能会返回与std::valarray<T>
不同的东西。
我不明白这样做的原因,但令人困惑的是the same seem to apply to operator*=
,除了我的auto
分配在这里起作用。我希望operator*=
和operator*
的返回值在这里是相同的(减去引用)。
所以我的问题是:
std::begin
/ std::end
不兼容的其他内容)?(注意:我标记了c ++ 11这个问题,但似乎也适用于所有版本,最高为17)
答案 0 :(得分:12)
有一个技巧叫表达式模板,它可以提高复合表达式的效率,但是使用auto
却会令人发指。
更改此:
auto w = v * 2;
对此:
std::valarray<int> w = v * 2;
您的代码有效。
要了解为什么要使用表达式模板,请尝试以下操作:
std::valarray<int> a={1,2,3},b{4,5,6},c={2,4,8};
std::valarray<int> r = (a+b*2)*c;
此处,表达式模板避免创建临时的valarray a+b*2
或b*2
,而是向下传递整个表达式,并使用逐元素操作构造r
。
在(a+b*2)*c
中没有创建三元素的valarray临时对象-只是描述表达式结构和参数的一系列对象。将表达式分配给实际的valarray
后,将在逐个元素的基础上对表达式进行求值。
但是auto
不会转换为valarray
;它只存储表达式模板对象。这样您的代码就会中断。
我不知道该标准的哪个版本允许这样做;不管怎样,某些valarray实现使用此方法,并且它增加了很多效率。没有它,valarray会很烂。