4

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>?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • If you replace `auto v3 = ...` with `std::valarray v3 = ...` the code compiles and runs as expected. By using `auto`, `v3` is some intermediate expression template generated type. – Praetorian Sep 25 '19 at 16:49
  • 1
    Operators on `valarray` are allowed to return proxy objects, which lets the implementation optimize multiple operations like `a * b + c` into a single loop. I don't know if the proxy objects need to implement `begin()` and `end()` or not. – interjay Sep 25 '19 at 16:49
  • See http://eel.is/c++draft/valarray.syn#3.sentence-1, which implies that you're not allowed to use `auto` and have the expectations on it that you're testing for. – Kerrek SB Sep 25 '19 at 16:53
  • Possible duplicate of [What's wrong with std::valarray's operator\*?](https://stackoverflow.com/questions/56222576/whats-wrong-with-stdvalarrays-operator) – metalfox Sep 27 '19 at 10:31

1 Answers1

5

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 and std::indirect_array can be constructed from the replacement type.
  • All functions accepting an argument of type const std::valarray& except begin() and end() (since C++11) should also accept the replacement type.
  • All functions accepting two arguments of type const std::valarray& should accept every combination of const 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.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402