Ксения (28.11.2017 14:49 - 14:53, просмотров: 740) ответил Evgeny_CD на Спасибо! Классно пояснили!
Я вообще-то свой метод открыла :), как обойти явную типизацию, хотя и не уверена, что кто-то не открыл его раньше: Пример - имеем две квадратных матрицы, размером 128x128, с элементами типа double:
Matrix M1(128,128), M2(128,128); // где Matrix - класс, аллокирующий им место в динамической памяти
Здесь без динамической памяти не обойтись, т.к. матрицы бывают очень большими, а их размер - переменной величиной, в момент компиляции неизвестной.
Из этих двух матриц можно получить целых 4 разных продукта их перемножения, в зависимости от их взаимной ориентации:
M = M1 * M2;
M = M1 * transpose(M2);
M = transpose(M1) * M2;
M = transpose(M1) * transpose(M2);
Рассмотрим последний случай, как, казалось бы, наиболее сложный - в нем сразу две матрицы приходится транспонировать.
Если делать это в лоб, то transpose() окажется функцией, которая будет вынуждена динамически проаллокировать новую матрицу транспонированного размера (т.е. по сути создать еще один объект типа Matrix), а потом скопировать туда данные из исходной матрицы "наперекосяк". Это накладно, т.к. транспонировать на том же месте в общем случае нельзя - исходная матрица может оказаться прямоугольной, не говоря уже о том, что портить аргумент нежелательно.
А теперь оцените изящество моего решения :). У меня transpose() не функция, а преобразование типа (!) Matrix в тип TransposeMatrix. Такое преобразование типов возможно ВСЕГДА, т.к. оба класса совершенно одинаково определены, а в данном случае и подавно, т.к. TransposeMatrix является для класса Matrix базовым (формальное определение, т.к. ничем от своего базового он не отличается - просто так создать класс-копию проще всего).
Никого лишнего кода при этом компилятор не генерирует: transpose(M2) выдает тот же адрес, что M2, но формально тип у этого адреса для самого компилятора сменился - стал TransposeMatrix вместо Matrix.
А дальше совсем просто - есть 4 функции Multiply(), различающихся типом параметров:
Multiply( &Mattix, &Mattix)
Multiply( &Mattix, &TransposeMattix)
Multiply( &TransposeMattix, &Mattix)
Multiply( &TransposeMattix, &TransposeMattix)
Каждая из которых выполняет умножение двух матриц, но у тех, где тип TransposeMattix индексы переставлены местами!
Например, M2[j][i] вместо M2[i][j]. Т.е. транспонирование производится не явно, а путем перестановки индексов.
Не трудно догадаться, что все 4 функции Multiply() написаны у меня на ассемблере с использованием AVX-инструкций :).
При этом C++ код, включающий неявную типизацию, ничего лишнего не добавляет, а сводится к прямому вызову нужного варианта ассеблерной функции Multiply().