I tried the following program
#include <iostream>
#include <valarray>
int main( void )
{
std::valarray<int> v1 = { 1, 2, 3, 4, 5 };
std::valarray<int> v2 = { 1, 2, 3, 4, 5 };
auto v3 = v1 * v2;
for ( const auto &item : v3 ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
and got an error message that an appropriate function begin
for v3
used implicitly in this statement
for ( const auto &item : v3 ) std::cout << item << ' ';
can not be found.
So I tried the following code
#include <iostream>
#include <valarray>
#include <type_traits>
int main( void )
{
std::valarray<int> v1 = { 1, 2, 3, 4, 5 };
std::valarray<int> v2 = { 1, 2, 3, 4, 5 };
auto v3 = v1 * v2;
std::cout << std::is_same<std::valarray<int>, decltype( v3 )>::value << '\n';
return 0;
}
and got the result
0
But when this statement
auto v3 = v1 * v2;
is changed to
std::valarray<int> v3 = v1 * v2;
then the output is
1
The operator *
for std::valarray<int>
is declared the following way
template<class T> valarray<T> operator* (const valarray<T>&, const valarray<T>&);
So is it a bug of the implementation of std::valarray<int>
?
This is not a bug. std::valarray::operator*
does not actually have to return a std::valarray
because it is allowed to use expression templates. That means it can return a type that has the following properties:
- All const member functions of
std::valarray
are provided.std::valarray
,std::slice_array
,std::gslice_array
,std::mask_array
andstd::indirect_array
can be constructed from the replacement type.- All functions accepting an argument of type
const std::valarray&
exceptbegin()
andend()
(since C++11) should also accept the replacement type.- All functions accepting two arguments of type
const std::valarray&
should accept every combination ofconst std::valarray&
and the replacement type.- The return type does not add more than two levels of template nesting over the most deeply-nested argument type.
emphasis mine source
Because of this, you need to explicitly capture the return as a std::valarray
so the specialization for std::begin
can be called.