Числовые типы. Срезы

   
На этом шаге мы рассмотрим использование срезов.

   
Срез определяется набором индексов, который характеризуется тремя свойствами:

  • начальным индексом;
  • количеством элементов (размером);
  • расстоянием между элементами (шагом).

   
Порядок передачи этих трех свойств точно соответствует порядку следования параметров конструктора класса slice. Например, следующее
выражение определяет четыре элемента, начиная с индекса 2, находящихся на расстоянии 3 друг от друга:

  std::slice(2,4,3)

   
Другими словами, выражение определяет такой набор индексов:

  2 5 8 11

   
Шаг может быть отрицательным. Например, рассмотрим следующее выражение:

  std::slice(9,5,-2)

   
Это выражение определяет такой набор индексов:

  9 7 5 3 1

   
Чтобы определить подмножество элементов массива значений, достаточно передать срез в качестве аргумента оператора индексирования. Например,
следующее выражение определяет подмножество массива va, содержащее элементы с индексами 2, 5, 8 и 11:

  va[std::slice(2,4,3)]

   
Перед вызовом необходимо проверить правильность всех индексов.

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

namespace std {
    class slice;

    template <class T>
    class slice_array;

    template <class T>
    class valarray {
      public:
        // Срез константного массива значений
        // возвращает новый массив значений
        valarray<T> operator[] (slice) const;

        // Срез неконстантного массива значений возвращает slice_array
        slice_array<T> operator[] (slice);
        ...
    };
}

   
Для объектов slice_array определены следующие операции:

  • присваивание одного значения всем элементам;
  • присваивание другого массива значений (или подмножества массива значений);
  • вызовы любых операций вычисляемого присваивания (с такими операторами, как += и *=).

   
Для остальных операций подмножество необходимо преобразовать в массив значений (смотри 433 шаг). Учтите, что
класс slice_array проектировался исключительно как внутренний вспомогательный класс для работы со срезами, поэтому он должен
оставаться невидимым для внешних пользователей. По этой причине все конструкторы и операторы присваивания класса slice_array<>
объявлены закрытыми.

   
Например, представленная ниже команда присваивает 2 третьему, шестому, девятому и двенадцатому элементам массива значений va:

  va[std::slice(2,4,3)] = 2;

   
Она эквивалентна следующему набору команд:

  va[2] = 2; 
  va[5] = 2; 
  va[8] = 2; 
  va[11] = 2;

   
Другая команда возводит в квадрат элементы с индексами 2, 5, 8 и 11:

  va[std::slice(2,4,3)] *= std::valarray<double>(va[std::slice(2,4,3)]);

   
Как упоминалось на 433 шаге, следующая запись является ошибочной:

  va[std::slice(2,4,3)] *= va[std::slice(2,4,3)]; // ОШИБКА

   
Но если воспользоваться шаблонной функцией VA() (смотри 433 шаг), запись принимает следующий вид:

  va[std::slice(2,4,3)] *= VA(va[std::slice(2,4,3)]); // OK

   
Передавая разные срезы одного массива значений, можно объединить подмножества и сохранить результат в другом подмножестве массива.
Например, рассмотрим такую команду:

  va[std::slice(0,4,3)] = VA(va[std::slice(1,4,3)]) * 
          VA(va[std::slice(*2,4,3)]);

   
Эта команда эквивалентна следующему набору команд:

  va[0] = va[1] * va[2]; 
  va[3] = va[4] * va[5]; 
  va[6] = va[7] * va[8]; 
  va[9] = va[10] * va[11];

   
Если рассматривать массив значений как двухмерную матрицу, этот пример представляет собой не что иное, как умножение векторов (рисунок 1).


Рис.1. Умножение векторов с использованием срезов

   
Однако следует учитывать, что порядок выполнения отдельных присваиваний не определен. Следовательно, если приемное подмножество содержит
элементы, используемые в исходном подмножестве, последствия могут быть непредсказуемыми.

   
Также возможны и более сложные команды. Например:

  va[std::slice(0,100,3)]
    = std::pow(VA(va[std::slice(l,100,3)]) * 5.0, 
                     VA(va[std::slice(2,100,3)]));

   
Еще раз обратите внимание: отдельное значение (5.0 в данном случае) должно точно соответствовать типу элементов массива значений.

   
На следующем шаге мы приведем пример использования срезов.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий