Шаг 434.
Библиотека STL.
Числовые типы. Срезы

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

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

    Порядок передачи этих трех свойств точно соответствует порядку следования параметров конструктора класса 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 в данном случае) должно точно соответствовать типу элементов массива значений.

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




Предыдущий шаг Содержание Следующий шаг