x.apply(f); // x[i] = f(x[i]) для каждого i
В результате a==b
и x==y
.
apply
называется f(x)
, а не apply(f,x)
. Для того чтобы эта возможность стала доступной для каждой функции f
(а не только для отдельных функций, как в языке Fortran), мы должны присвоить операции пересылки конкретное имя, поэтому (повторно) использовали имя apply.
Кроме того, для того чтобы обеспечить соответствие с вариантом функции-члена apply
, имеющим вид a.apply(f,x)
, мы пишем
b = apply(f,a,x); // b[i]=f(a[i],x) для каждого i
Рассмотрим пример.
double scale(double d, double s) { return d*s; }
b = apply(scale,a,7); // b[i] = a[i]*7 для каждого i
Обратите внимание на то, что “автономная” функция apply()
принимает в качестве аргумента функцию, вычисляющую результат по ее аргументам, а затем использует этот результат для инициализации итогового объекта класса Matrix
. Как правило, это не приводит к изменению объекта класса Matrix
, к которому эта функция применяется. В то же время функция-член apply()
отличается тем, что принимает в качестве аргумента функцию, модифицирующую ее аргументы; иначе говоря, она модифицирует элементы объекта класса Matrix
, к которому применяется. Рассмотрим пример.
void scale_in_place(double& d, double s) { d *= s; }
b.apply(scale_in_place,7); // b[i] *= 7 для каждого i
В классе Matrix
предусмотрено также много полезных функций из традиционных математических библиотек.
Matrix
// и сложение
int r = dot_product(a3,a); // скалярное произведение
scale_and_add()
часто называют result(i)=arg1(i)*arg2+arg3(i)
для каждого i
в объекте класса Matrix
. Скалярное произведение также известно под именем inner_product
и описано в разделе 21.5.3; ее определение выглядит так: result+=arg1(i)*arg2(i)
для каждого i
в объекте класса Matrix
, где накопление объекта result
начинается с нуля.
Одномерные массивы очень широко распространены; их можно представить как в виде встроенного массива, так и с помощью классов vector
и Matrix
. Класс Matrix
следует применять тогда, когда необходимо выполнять матричные операции, такие как *=
, или когда объект класса Matrix
должен взаимодействовать с другими объектами этого класса, имеющими более высокую размерность.
Matrix
, например копирование, присваивание всем элементам и операции над всеми элементами, позволяют не использовать циклы (а значит, можно не беспокоиться о связанных с ними проблемах).
Класс Matrix
имеет два конструктора для копирования данных из встроенных массивов в объект класса Matrix
. Рассмотрим пример.
void some_function(double* p, int n)
{
double val[] = { 1.2, 2.3, 3.4, 4.5 };
Matrix
Matrix
// ...
}
Это часто бывает полезным, когда мы получаем данные в виде обычных массивов или векторов, созданных в других частях программы, не использующих объекты класса Matrix
.
Обратите внимание на то, что компилятор может самостоятельно определить количество элементов в инициализированном массиве, поэтому это число при определении объекта constants
указывать не обязательно — оно равно — 4
. С другой стороны, если элементы заданы всего лишь указателем, то компилятор не знает их количества, поэтому при определении объекта data
мы должны задать как указатель p
, так и количество элементов n
.
24.5.3. Двумерный объект класса Matrix
Общая идея библиотеки Matrix
заключается в том, что матрицы разной размерности на самом деле в большинстве случаев очень похожи, за исключением ситуаций, в которых необходимо явно указывать размерность. Таким образом, большинство из того, что мы можем сказать об одномерных объектах класса Matrix
, относится и к двумерным матрицам.