Класс valarray: динамический массив с числовыми значениями

Класс valarray реализует динамический массив с числовыми значениями. Обратите внимание: этот класс не входит в состав STL. Прежде чем использовать класс, необходимо в начало программы добавить инструкцию:

#include <valarray>

Создание объекта

Объявление класса valarray:

template<class _Tp> class valarray;

Для обобщенного типа _Tp создан псевдоним value_type:

typedef _Tp value_type;

Создать объект можно следующими способами (полный список конструкторов смотрите в документации):

  • объявить переменную без инициализации. Для этого перед названием переменной указывается название класса, а после названия внутри угловых скобок задается числовой тип данных. В этом случае массив не содержит элементов. Пример объявления без инициализации:
std::valarray<int> arr;
std::cout << arr.size() << std::endl; // 0
  • указать внутри круглых скобок количество элементов. Все элементы будут иметь значения по умолчанию для типа. Например, для типа int все элементы будут содержать значение 0:
std::valarray<int> arr(5);
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 0 0 0 0 0
  • в первом параметре указать значение, а во втором — количество элементов. Пример создания массива из 5 элементов со значением 1:
std::valarray<int> arr(1, 5);
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 1 1 1 1
  • перечислить значения через запятую внутри фигурных скобок:
std::valarray<int> arr1{1, 2, 3};
for (int &el : arr1) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
std::valarray<int> arr2 = {4, 5, 6};
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 4 5 6
  • указать объект класса valarray внутри круглых скобок или после оператора = (доступны конструкторы копирования и перемещения):
std::valarray<int> arr1 = {1, 2, 3};
// Создание копии
std::valarray<int> arr2(arr1);
arr2[0] = 55;
for (int &el : arr1) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 55 2 3
// Перемещение элементов
std::valarray<int> arr3(std::move(arr1));
for (int &el : arr3) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
std::cout << arr1.size() << std::endl; // 0
  • в первом параметре передать указатель на обычный массив, а во втором — количество элементов:
const int ARR_SIZE = 3;
int arr[ARR_SIZE] = {1, 2, 3};
std::valarray<int> arr2(arr, ARR_SIZE);
arr2[0] = 55;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 55 2 3
  • указав диапазон с помощью следующих конструкторов:
valarray(const slice_array<_Tp> &sa);
valarray(const gslice_array<_Tp> &ga);
valarray(const mask_array<_Tp> &ma);
valarray(const indirect_array<_Tp> &ia);

Пример (первое значение в конструкторе класса slice означает начальный индекс, второе — количество элементов, а третье — шаг):

std::valarray<int> arr1 = {1, 2, 3, 4, 5, 6};
std::valarray<int> arr2(arr1[std::slice(1, 4, 1)]);
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 2 3 4 5

Один объект можно присвоить другому объекту того же размера. В этом случае выполняется поэлементное копирование (оператор копирования) или перемещение элементов (оператор перемещения). Пример:

std::valarray<int> arr1 = {1, 2, 3}, arr2(0, 3), arr3(0, 3);
// Создание копии
arr2 = arr1;
arr2[0] = 55;
for (int &el : arr1) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 55 2 3
// Перемещение элементов
arr3 = std::move(arr1);
for (int &el : arr3) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
std::cout << arr1.size() << std::endl; // 0

Доступно также присваивание элементов из списка инициализации:

std::valarray<int> arr(0, 3);
arr = {1, 2, 3};
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3

Если присвоить какое-либо числовое значение, то каждый элемент массива будет иметь это значение:

std::valarray<int> arr = {1, 2, 3};
arr = 5;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 5 5 5

Следующие прототипы позволяют присвоить диапазон значений:

valarray<_Tp> &operator=(const slice_array<_Tp> &sa);
valarray<_Tp> &operator=(const gslice_array<_Tp> &ga);
valarray<_Tp> &operator=(const mask_array<_Tp> &ma);
valarray<_Tp> &operator=(const indirect_array<_Tp> &ia);

Обратите внимание: размеры должны совпадать, иначе результат присваивания не определен. Пример:

std::valarray<int> arr1 = {1, 2, 3, 4, 5, 6};
std::valarray<int> arr2(0, 4);
arr2 = arr1[std::slice(1, 4, 1)];
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 2 3 4 5

Метод swap() позволяет поменять элементы двух массивов местами:

std::valarray<int> arr1 = {1, 2, 3}, arr2 = {4, 5, 6};
arr1.swap(arr2);
for (int &el : arr1) std::cout << el << ' ';
std::cout << std::endl; // 4 5 6
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3

Определение и изменение количества элементов

Получить количество элементов массива позволяет метод size(). Прототип метода:

size_t size() const;

Пример:

std::valarray<int> arr = {1, 2, 3};
std::cout << arr.size() << std::endl; // 3

Для изменения размера массива предназначен метод resize(). Предыдущее содержимое массива будет потеряно. Прототип метода:

void resize(size_t size, _Tp val = _Tp());

После изменения размера все элементы массива получат значение, указанное в параметре val:

std::valarray<int> arr = {1, 2, 3};
std::cout << arr.size() << std::endl; // 3
arr.resize(2);
std::cout << arr.size() << std::endl; // 2
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl;               // 0 0
arr.resize(5, 44);
std::cout << arr.size() << std::endl; // 5
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl;               // 44 44 44 44 44

Доступ к элементам

К любому элементу можно обратиться как к элементу обычного массива. Достаточно указать его индекс в квадратных скобках. Нумерация начинается с нуля. Можно как получить значение, так и изменить его. Если индекс выходит за границы диапазона, то возвращаемое значение не определено. Пример доступа к элементу по индексу:

std::valarray<int> arr = {1, 2, 3};
std::cout << arr[0] << std::endl; // 1
arr[0] = 55;
std::cout << arr[0] << std::endl; // 55

Получить итератор, указывающий на начало массива, позволяет функция begin(). Прототипы функции:

template<typename _Tp> _Tp *begin(valarray<_Tp> &v);
template<typename _Tp> const _Tp *begin(const valarray<_Tp> &v);

Получим и изменим значение первого элемента массива:

std::valarray<int> arr = {1, 2, 3};
auto it = std::begin(arr);
std::cout << *it << std::endl; // 1
*it = 0;
std::cout << *it << std::endl; // 0

Функция end() возвращает итератор, указывающий на позицию после последнего элемента. Прототипы функции:

template<typename _Tp> _Tp *end(valarray<_Tp> &v);
template<typename _Tp> const _Tp *end(const valarray<_Tp> &v);

Выведем значение последнего элемента:

std::valarray<int> arr = {1, 2, 3};
auto it = std::end(arr);
std::cout << *(--it) << std::endl; // 3

Перебор элементов

Перебрать все элементы можно с помощью цикла for each и итераторов. Пример использования цикла for each:

std::valarray<int> arr(3);
// Заполняем массив значениями
int n = 1;
for (int &el : arr) {
   el = n++;
}
// Выводим значения
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3

Если нужен доступ по индексу, то можно воспользоваться циклом for:

std::valarray<int> arr = {1, 2, 3};
for (size_t i = 0, j = arr.size(); i < j; ++i)
   std::cout << arr[i] << ' ';
std::cout << std::endl; // 1 2 3

Пример перебора элементов с помощью итераторов и цикла for:

std::valarray<int> arr = {1, 2, 3};
for (auto it1 = std::begin(arr), it2 = std::end(arr);
     it1 != it2; ++it1) {
   std::cout << *it1 << ' ';
}
std::cout << std::endl; // 1 2 3

Пример перебора элементов с помощью итераторов и цикла while:

std::valarray<int> arr = {1, 2, 3};
auto it1 = std::begin(arr), it2 = std::end(arr);
while (it1 != it2) {
   std::cout << *it1++ << ' ';
}
std::cout << std::endl; // 1 2 3

Поиск минимального и максимального значений

Для поиска минимального и максимального значений предназначены следующие методы:

  • min() — выполняет поиск минимального значения в массиве и возвращает элемент. Если массив не содержит элементов, то возвращаемое значение не определено. Обратите внимание: обобщенный тип _Tp должен поддерживать сравнение с помощью оператора <. Прототип метода:
_Tp min() const;

Пример:

std::valarray<int> arr = {1, 2, 3};
std::cout << arr.min() << std::endl; // 1
  • max() — выполняет поиск максимального значения в массиве и возвращает элемент. Если массив не содержит элементов, то возвращаемое значение не определено. Обратите внимание: обобщенный тип _Tp должен поддерживать сравнение с помощью оператора <. Прототип метода:
_Tp max() const;

Пример:

std::valarray<int> arr = {1, 2, 3};
std::cout << arr.max() << std::endl; // 3

Смещение элементов

Метод shift() выполняет смещение элементов на расстояние n, которое может быть как положительным, так и отрицательным. Метод возвращает копию массива, в котором элементы вышедшие за пределы массива будут удалены, а новые элементы получат значения по умолчанию для типа. Прототип метода:

valarray<_Tp> shift(int n) const;

Пример:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::valarray<int> arr2(arr.shift(3));
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 4 5 0 0 0
std::valarray<int> arr3(arr.shift(-3));
for (int &el : arr3) std::cout << el << ' ';
std::cout << std::endl; // 0 0 0 1 2

Метод cshift() выполняет смещение элементов на расстояние n, которое может быть как положительным, так и отрицательным. Метод возвращает копию массива, в котором элементы вышедшие за пределы массива будут вставлены с другой стороны. Метод как бы вращает элементы внутри массива, при этом не меняя их последовательность. Прототип метода:

valarray<_Tp> cshift(int n) const;

Пример:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::valarray<int> arr2(arr.cshift(3));
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 4 5 1 2 3
std::valarray<int> arr3(arr.cshift(-3));
for (int &el : arr3) std::cout << el << ' ';
std::cout << std::endl; // 3 4 5 1 2

Вычисление суммы

Вычислить сумму всех значений элементов массива позволяет метод sum(). Обратите внимание: обобщенный тип _Tp должен поддерживать оператор +=. Если массив не содержит элементов, то возвращаемое значение не определено. Прототип метода:

_Tp sum() const;

Пример:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::cout << arr.sum() << std::endl; // 15

Операторы и функции

Над двумя объектами класса valarray, а также над объектом и значением определены логические операции ==, !=, <, <=, >, >=, && и ||. Если в операции участвуют два объекта, то сравниваются значения элементов, расположенных на одинаковом смещении. Результатом будет объект valarray с логическими значениями, соответствующими результату сравнения:

std::valarray<int> arr1 = {1, 2, 3}, arr2 = {0, 2, 3};
std::valarray<bool> result = (arr1 == arr2);
std::cout << std::boolalpha;
for (bool &el : result) std::cout << el << ' ';
std::cout << std::endl; // false true true

Если справа или слева от логического оператора расположено значение, а с другой стороны объект valarray, то каждый элемент массива сравнивается с этим значением. Результатом будет объект valarray с логическими значениями, соответствующими результату сравнения:

std::valarray<int> arr = {1, 2, 3};
std::valarray<bool> result = (arr <= 2);
std::cout << std::boolalpha;
for (bool &el : result) std::cout << el << ' ';
std::cout << std::endl; // true true false

Поддерживается также унарный логический оператор !, позволяющий изменить каждое логическое значение на противоположное:

std::valarray<int> arr = {1, 2, 3};
std::valarray<bool> result = (!(arr <= 2));
std::cout << std::boolalpha;
for (bool &el : result) std::cout << el << ' ';
std::cout << std::endl; // false false true

Аналогичным образом можно использовать математические операторы +, -, *, / и %, а также побитовые операторы &, |, ^, << и >>. Результатом будет объект valarray с новыми значениями:

std::valarray<int> arr1 = {1, 2, 3}, arr2 = {0, 2, 3};
// Два объекта valarray
std::valarray<int> result = arr1 + arr2;
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1 4 6
// Объект valarray и значение (справа или слева от оператора)
std::valarray<int> result2 = arr1 * 2;
for (int &el : result2) std::cout << el << ' ';
std::cout << std::endl; // 2 4 6

Доступны также математические операторы с присваиванием +=, -=, *=, /= и %=, а также побитовые операторы с присваиванием &=, |=, ^=, <<= и >>=. Операции изменяют текущий объект:

std::valarray<int> arr1 = {1, 2, 3}, arr2 = {1, 2, 3};
// Два объекта valarray
arr1 += arr2;
for (int &el : arr1) std::cout << el << ' ';
std::cout << std::endl; // 2 4 6
// Объект valarray и значение
arr2 += 2;
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 3 4 5

Существует возможность использования математических унарных операторов + и -, а также побитового унарного оператора ~. Результатом будет объект valarray с новыми значениями:

std::valarray<int> arr = {1, 2, 3};
std::valarray<int> result = -arr;
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // -1 -2 -3

Перечислим основные функции для работы с объектами valarray (полный список функций смотрите в документации):

  • abs() — вычисляет абсолютное значение каждого элемента массива и возвращает объект с новыми значениями:
std::valarray<int> arr = {1, -2, -3};
std::valarray<int> result = std::abs(arr);
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1 2 3
  • pow() — возводит каждое значение массива в степень:
std::valarray<int> arr = {1, 2, 3};
std::valarray<int> result = std::pow(arr, 2);
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1 4 9

Значения степеней можно задать элементами объекта valarray:

std::valarray<int> arr = {10, 3}, arr2 = {2, 3};
std::valarray<int> result = std::pow(arr, arr2);
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // 100 27
  • sqrt() — вычисляет квадратный корень:
std::valarray<int> arr = {25, 100};
std::valarray<int> result = std::sqrt(arr);
for (int &el : result) std::cout << el << ' ';
std::cout << std::endl; // 5 10
  • exp() — вычисляет экспоненту:
std::valarray<double> arr = {1.1, 2.2};
std::valarray<double> result = std::exp(arr);
for (double &el : result) std::cout << el << ' ';
std::cout << std::endl; // 3.00417 9.02501
  • log() — вычисляет натуральный логарифм:
std::valarray<double> arr = {5.0, 8.0};
std::valarray<double> result = std::log(arr);
for (double &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1.60944 2.07944
  • log10() — вычисляет десятичный логарифм:
std::valarray<double> arr = {10.0, 100.0};
std::valarray<double> result = std::log10(arr);
for (double &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1 2
  • sin(), cos(), tan() — стандартные тригонометрические функции (синус, косинус, тангенс):
std::valarray<double> arr = {1.5708, 0.785398};
std::valarray<double> result = std::sin(arr);
for (double &el : result) std::cout << el << ' ';
std::cout << std::endl; // 1 0.707107
  • asin(), acos(), atan() — обратные тригонометрические функции (арксинус, арккосинус, арктангенс).

Применить к каждому элементу массива пользовательскую функцию позволяет метод apply(). В качестве значения метод возвращает новый массив. Прототипы метода:

valarray apply(_Tp func(_Tp x)) const;
valarray apply(_Tp func(const _Tp &x)) const;

Умножим каждое значение на 2:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::valarray<int> arr2(arr.apply( [](int x){ return x * 2; } ));
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 2 4 6 8 10

Классы slice и slice_array: диапазон значений

Класс slice позволяет задать диапазон значений. Конструкторы класса:

slice();
slice(size_t start, size_t size, size_t stride);

Параметр start задает начальный индекс, параметр size — количество элементов, а параметр stride — шаг. Получить эти значения после создания объекта позволяют методы start(), size() и stride(). Прототипы методов:

size_t start() const;
size_t size() const;
size_t stride() const;

Пример создания объекта и получения значений:

std::slice obj(1, 4, 2);
std::cout << obj.start() << std::endl;  // 1
std::cout << obj.size() << std::endl;   // 4
std::cout << obj.stride() << std::endl; // 2

Можно создать копию объекта или выполнить перемещение:

std::slice obj1(1, 4, 2);
std::slice obj2(obj1);
std::cout << obj2.start() << std::endl;  // 1
std::cout << obj2.size() << std::endl;   // 4
std::cout << obj2.stride() << std::endl; // 2

Для получения диапазона значений (среза) массива нужно указать объект класса slice внутри квадратных скобок:

slice_array<_Tp> operator[](slice s);
valarray<_Tp> operator[](slice s) const;

Результатом операции будет объект промежуточного класса slice_array или объект, который может быть преобразован в объект valarray. Объявление класса slice_array:

template<typename _Tp> class slice_array;

В классе slice_array доступен только конструктор копирования, поэтому создать объект этого класса другим способом нельзя. Для преобразования объекта класса slice_array в массив нужно передать его конструктору класса valarray или выполнить присваивание (размеры объектов должны совпадать, иначе результат присваивания не определен). Получим четыре элемента, начиная со второго (элемента с индексом 1):

std::valarray<int> arr1 = {1, 2, 3, 4, 5, 6};
std::valarray<int> arr2 = arr1[std::slice(1, 4, 1)];
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 2 3 4 5

Объект класса slice_array содержит ссылки на элементы исходного массива. Все изменения этого объекта приведут к изменениям в исходном массиве. Например, присвоим нулевое значение всем элементам с четными индексами:

std::valarray<int> arr = {1, 2, 3, 4, 5, 6};
arr[std::slice(1, 3, 2)] = 0;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 0 3 0 5 0

В классе slice_array перегружены следующие операторы:

void operator=(const _Tp &n) const;
slice_array &operator=(const slice_array &s);
void operator=(const valarray<_Tp> &v) const;
void operator+=(const valarray<_Tp> &v) const;
void operator-=(const valarray<_Tp> &v) const;
void operator*=(const valarray<_Tp> &v) const;
void operator/=(const valarray<_Tp> &v) const;
void operator%=(const valarray<_Tp> &v) const;
void operator&=(const valarray<_Tp> &v) const;
void operator|=(const valarray<_Tp> &v) const;
void operator^=(const valarray<_Tp> &v) const;
void operator<<=(const valarray<_Tp> &v) const;
void operator>>=(const valarray<_Tp> &v) const;

Классы gslice и gslice_array: несколько диапазонов значений

Класс gslice позволяет задать сразу несколько диапазонов значений. Конструкторы класса:

gslice();
gslice(size_t start, const valarray<size_t> &sizes,
       const valarray<size_t> &strides);
gslice(const gslice &obj);

Параметр start задает начальный индекс, параметр sizes — количество элементов в виде объекта класса valarray, а параметр strides — шаг в виде объекта класса valarray. Получить эти значения после создания объекта позволяют методы start(), size() и stride(). Прототипы методов:

size_t start() const;
valarray<size_t> size() const;
valarray<size_t> stride() const;

Пример создания объекта и получения значений:

std::gslice obj(1, std::valarray<size_t>{2, 3},
                   std::valarray<size_t>{5, 1});
std::cout << obj.start() << std::endl;  // 1
std::valarray<size_t> sizes = obj.size();
for (size_t &el : sizes) std::cout << el << ' ';
std::cout << std::endl;                 // 2 3
std::valarray<size_t> strides = obj.stride();
for (size_t &el : strides) std::cout << el << ' ';
std::cout << std::endl;                 // 5 1

Для получения диапазона значений (среза) массива нужно указать объект класса gslice внутри квадратных скобок:

gslice_array<_Tp> operator[](const gslice &s);
valarray<_Tp> operator[](const gslice &s) const;

Результатом операции будет объект промежуточного класса gslice_array или объект, который может быть преобразован в объект valarray. Объявление класса gslice_array:

template<typename _Tp> class gslice_array;

В классе gslice_array доступен только конструктор копирования, поэтому создать объект этого класса другим способом нельзя. Для преобразования объекта класса gslice_array в массив нужно передать его конструктору класса valarray или выполнить присваивание (размеры объектов должны совпадать, иначе результат присваивания не определен). Пример:

std::gslice obj(1, std::valarray<size_t>{2, 3},
                   std::valarray<size_t>{5, 1});
std::valarray<int> arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::valarray<int> arr2 = arr1[obj];
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 2 3 4 7 8 9

Почему мы получили шесть элементов, а не пять? Ведь при сложении первого количества элементов (2) со вторым (3) вроде как получается 5. Давайте разберемся. Вначале определяются элементы первого среза. Мы указали 2 элемента с шагом 5. Это значения 2 и 7. Далее от этих двух значений отсчитываются элементы второго среза. Мы указали 3 элемента с шагом 1. Первые три элемента отсчитываются от первого элемента первого среза, а вторые три элемента — от второго элемента первого среза. Итого получается шесть элементов. Схематично это выглядит так:

arr1:    1 2 3 4 5 6 7 8 9 10
(2, 5):    *---------*
           |         |
(3, 1):    *-*-*     *-*-*
Итог:      2 3 4     7 8 9

Объект класса gslice_array содержит ссылки на элементы исходного массива. Все изменения этого объекта приведут к изменениям в исходном массиве. Например, присвоим нулевое значение всем элементам из среза:

std::gslice obj(1, std::valarray<size_t>{2, 3},
                   std::valarray<size_t>{5, 1});
std::valarray<int> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
arr[obj] = 0;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 1 0 0 0 5 6 0 0 0 10

В классе gslice_array перегружены следующие операторы:

void operator=(const _Tp &n) const;
gslice_array &operator=(const gslice_array &s);
void operator=(const valarray<_Tp> &v) const;
void operator+=(const valarray<_Tp> &v) const;
void operator-=(const valarray<_Tp> &v) const;
void operator*=(const valarray<_Tp> &v) const;
void operator/=(const valarray<_Tp> &v) const;
void operator%=(const valarray<_Tp> &v) const;
void operator&=(const valarray<_Tp> &v) const;
void operator|=(const valarray<_Tp> &v) const;
void operator^=(const valarray<_Tp> &v) const;
void operator<<=(const valarray<_Tp> &v) const;
void operator>>=(const valarray<_Tp> &v) const;

Класс mask_array: диапазон на основе маски

Промежуточный класс mask_array позволяет получить доступ к элементам, для которых соответствующие по позиции элементы внутри массива с логическими значениями имеют значение true. Массив с маской можно создать с помощью операторов сравнения (см. разд. 16.3.8). Объявление класса mask_array:

template <class _Tp> class mask_array;

В классе mask_array доступен только конструктор копирования, поэтому создать экземпляр класса с помощью конструктора нельзя. Для создания объекта следует указать массив с логическими значениями внутри квадратных скобок:

mask_array<_Tp> operator[](const valarray<bool> &m);
valarray<_Tp> operator[](const valarray<bool> &m) const;

Для преобразования объекта класса mask_array в массив нужно передать его конструктору класса valarray или выполнить присваивание (размеры объектов должны совпадать, иначе результат присваивания не определен). Получим элементы со значениями меньшими или равными 2:

std::valarray<int> arr = {1, 2, 3};
std::valarray<bool> mask = (arr <= 2);
std::cout << std::boolalpha;
for (bool &el : mask) std::cout << el << ' ';
std::cout << std::endl; // true true false
std::valarray<int> arr2(arr[mask]);
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 1 2

В классе mask_array перегружены следующие операторы:

void operator=(const _Tp &n) const;
mask_array &operator=(const mask_array &m);
void operator=(const valarray<_Tp> &v) const;
void operator+=(const valarray<_Tp> &v) const;
void operator-=(const valarray<_Tp> &v) const;
void operator*=(const valarray<_Tp> &v) const;
void operator/=(const valarray<_Tp> &v) const;
void operator%=(const valarray<_Tp> &v) const;
void operator&=(const valarray<_Tp> &v) const;
void operator|=(const valarray<_Tp> &v) const;
void operator^=(const valarray<_Tp> &v) const;
void operator<<=(const valarray<_Tp> &v) const;
void operator>>=(const valarray<_Tp> &v) const;

Присвоим нулевое значение всем элементам со значениями меньшими или равными 2:

std::valarray<int> arr = {1, 2, 3};
arr[arr <= 2] = 0;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 0 0 3

Класс indirect_array: диапазон на основе массива с индексами

Промежуточный класс indirect_array позволяет получить доступ к элементам на основе значений массива с индексами. Объявление класса indirect_array:

template <class _Tp> class indirect_array;

В классе indirect_array доступен только конструктор копирования, поэтому создать экземпляр класса с помощью конструктора нельзя. Для создания объекта следует указать массив с индексами внутри квадратных скобок:

indirect_array<_Tp> operator[](const valarray<size_t> &i);
valarray<_Tp> operator[](const valarray<size_t> &i) const;

Для преобразования объекта класса indirect_array в массив нужно передать его конструктору класса valarray или выполнить присваивание (размеры объектов должны совпадать, иначе результат присваивания не определен). Получим элементы с индексами 0, 2 и 4:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::valarray<size_t> sel = {0, 2, 4};
std::valarray<int> arr2(arr[sel]);
for (int &el : arr2) std::cout << el << ' ';
std::cout << std::endl; // 1 3 5

В классе indirect_array перегружены следующие операторы:

void operator=(const _Tp &n) const;
indirect_array &operator=(const indirect_array &i);
void operator=(const valarray<_Tp> &v) const;
void operator+=(const valarray<_Tp> &v) const;
void operator-=(const valarray<_Tp> &v) const;
void operator*=(const valarray<_Tp> &v) const;
void operator/=(const valarray<_Tp> &v) const;
void operator%=(const valarray<_Tp> &v) const;
void operator&=(const valarray<_Tp> &v) const;
void operator|=(const valarray<_Tp> &v) const;
void operator^=(const valarray<_Tp> &v) const;
void operator<<=(const valarray<_Tp> &v) const;
void operator>>=(const valarray<_Tp> &v) const;

Присвоим нулевое значение всем элементам с индексами 0, 2 и 4:

std::valarray<int> arr = {1, 2, 3, 4, 5};
std::valarray<size_t> sel = {0, 2, 4};
arr[sel] = 0;
for (int &el : arr) std::cout << el << ' ';
std::cout << std::endl; // 0 2 0 4 0

Учебник C++ (Qt Creator и MinGW)
Учебник C++ (Qt Creator и MinGW) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов