Шаблон статического вектора
template <int n, typename T>
class Vector_static {
private:
T m_data[n];
public:
Vector_static(T x1, T x2, T x3, T x4) ...?
...
А теперь как сделать конструктор, в который бы передавались
значения координат? Разумеется, все ограничено длиной в 4 элемента. Специализация шаблона может быть только функциональной, а не структурной. А так бы можно было сделать объединение с нужным числом элементарных элементов для 4-х конкретизаций и дело в шляпе...
Думаю, придется делать отдельные классы для первых четырех...а жаль :(
Но уж если извращаться, до до конца... и в академических интересах.
Не применяй на практике конкретно эти варианты, т.к. они лишь усложнят простую задачу. Но методы решения запомни, могут пригодиться в реальных условиях.
Вариант 1
Можно, просто, сделать четыре вида конструкторов (поколичеству аргументов).
Можно воспользоваться макрсом BOOST_PP_REPEAT из библиотеки boost и нагенерить их, чтоб не писать вручную. Хотя для четырех вариантов проще воспользоваться Copy/Paste.
Чтоб пользователь случайно не вызвал не тот конструктор, сделать внутри конструктора проверку на кол-во аргументов.
{ typedef char check[N==4?1:0]; }
.....
}
Vector_static(T x1, T x2, T x3) {
{ typedef char check[N==3?1:0]; }
.....
}
Если пользователь ошибется с кол-вом аргументов конструктора, то компиляция обломится, но вот с неинформативным сообщением.
Вариант 2
Можно создать один конструктор со значениями параметров поумолчанию.
А далее внутри взять ровно столько значений, сколько надо.
Для этого нужен некоторый промежуточный "преобразователь", который из "перечисления" сделает "массив" значений, чтоб можно было итерироваться. В качестве такого "преобразователя" сойдет твой же класс:
Vector_static<4, T> transformer(x1, x2, x3, x4);
for(int i=0; i<N; ++i) {
m_data = transformer.m_data;
}
}
Компилятор от цикла, по идее, должен будет избавиться.
Накладные расходы будут с созданием объекта-трансформера.
Хотя, умный компилятор может это дело и оптимизировать.
Оптимизация варианта 2. Без слов :) :
switch(4-N) {
case 0: m_data[3] = x4;
case 1: m_data[2] = x3;
case 2: m_data[1] = x2;
case 3: m_data[0] = x1;
}
}
Для меня очень критична скорость работы программы, т.к. это курсовая работа и и должна быть посчитана к среде. А считает она дней 8 на двухядерном процессоре. Распараллеливание впринципе меня устраивает, коэффициент 1.93, алгоритм достаточно простой, в основном обычное умножение и сложение. Прогонял профилировщиком, нашел, что работа с матрицами и векторами занимает львиную долю, правда в основном на доступ к элементам, а не конструкторам. Поэтому и решил извратом заняться...
На самом деле я хотел выполнить инициализацию при конструировании:
m_x1(x1),
m_x2(x2)
{
}
Думая, что это увеличит производительность хоть на немного, но такая инициализация равносильна обычному присваиванию.
Кстати, оригинальное решение, еще не встречал :)
Тогда в случае ошибки пользователя, будет выводиться ошибка линковки.
class Vector_static {
public:
Vector_static(T x1);
Vector_static(T x1, T x2);
Vector_static(T x1, T x2, T x3);
Vector_static(T x1, T x2, T x3, T x4);
};
template<>
Vector_static<1>::Vector_static(T x1) {
}
template<>
Vector_static<2>::Vector_static(T x1, T x2) {
}
..........
Для меня очень критична скорость работы программы, т.к. это курсовая работа и и должна быть посчитана к среде. А считает она дней 8 на двухядерном процессоре. Распараллеливание впринципе меня устраивает, коэффициент 1.93, алгоритм достаточно простой, в основном обычное умножение и сложение. Прогонял профилировщиком, нашел, что работа с матрицами и векторами занимает львиную долю, правда в основном на доступ к элементам, а не конструкторам. Поэтому и решил извратом заняться...
На самом деле я хотел выполнить инициализацию при конструировании:
m_x1(x1),
m_x2(x2)
{
}
Думая, что это увеличит производительность хоть на немного, но такая инициализация равносильна обычному присваиванию.
Кстати, оригинальное решение, еще не встречал :)
Не там ищешь тормоза! Однозначно, не там!
Либо алгоритм не той сложности (я про О-большое), либо слишком много лишних операций.
Вот ты пытаешься оптимизировать создание объекта. И сколько ты на этом выиграешь? Какие-то доли процента.
А ведь оптимизация бывает не только "изнутри", но и "снаружи".
Может стоит оптимизировать не создание объекта, а количестве создаваемых, пересоздаваемых объектов?
Как элементарный пример: передавать объекты не по значению, а по ссылке (я бы за передачу по значению руки бы обрывал).
Кешировать результат, чтоб не пересчитывать одно и тоже по нескольку раз.
Многократно использовать уже готовые объекты (пул объектов), чтоб не конструировать заново.
Ты сам подумай, что должна делать программа, чтоб загрузить комп на 8 дней? :o
Это такая грубая ошибка: скатываться на низкоуровневую оптимизацию не проделав высокоуровневую. На низкоуровневой оптимизации выигрывают считанные проценты производительности. Ну ускоришь ты свою программу на 1%, будет она считаться не 8 дней, а 7 дней и 22 часа. Эти 2 часа тебя устроят? Сколько ты уже потерял времени? Думаю, больше этих 2х часов.
Не туда копаешь! Смотри алгоритм и реализацию.
P.S.
Я частенько даю такую задачу на собеседовании:
эта математическая функция работает очень медленно:
ускорьте работу программы. :)
Алгоритм с линейной зависимостью от размера и требуемой точности. Если увеличили в N раз размер, то в N раз считать будет дольше, с точностью тоже самое. А загрузить на столько запросто можно, сам в это раньше не верил. Программа расчитывает процессы газовой динамики в ракетном двигателе, чем более мелкая задана сетка, тем больше узлов надо считать, мне надо порядка 120 тысяч. По точности нужно идти с шагом в 1E-6 миллисекунды и достичь нужно где-то 3 миллисекунды. Т.е. где-то 3 млн. итераций. Время одной итерации где-то 200, 250 миллисекунд. Арифметика простая.