Предположим, у меня есть функция вычисления длины вектора, у которой есть дополнительный параметр inc
(он сообщает расстояние между соседними элементами). Простая реализация:
float calcLength(const float *v, int size, int inc) {
float l = 0;
for (int i=0; i<size*inc; i += inc) {
l += v[i]*v[i];
}
return sqrt(l);
}
Теперь calcLength
можно вызывать с двумя типами inc
параметров: когда inc
известен во время компиляции, и когда нет. Я хотел бы иметь оптимизированную версию calcLength
для общих значений времени компиляции inc
(например, 1).
Итак, у меня было бы что-то вроде этого:
template <int C>
struct Constant {
static constexpr int value() {
return C;
}
};
struct Var {
int v;
constexpr Var(int p_v) : v(p_v) { }
constexpr int value() const {
return v;
}
};
template <typename INC>
float calcLength(const float *v, int size, INC inc) {
float l = 0;
for (int i=0; i<size*inc.value(); i += inc.value()) {
l += v[i]*v[i];
}
return sqrt(l);
}
}
Итак, это можно использовать:
calcLength(v, size, Constant<1>()); // inc is a compile-time constant 1 here, calcLength can be vectorized
or
int inc = <some_value>;
calcLength(v, size, Var(inc)); // inc is a non-compile-time constant here, less possibilities of compiler optimization
Мой вопрос: можно ли каким-то образом сохранить исходный интерфейс и автоматически вставить _11 _ / _ 12_, в зависимости от типа (константа времени компиляции или нет) inc
?
calcLength(v, size, 1); // this should end up calcLength(v, size, Constant<1>());
calcLength(v, size, inc); // this should end up calcLength(v, size, Var(int));
Примечание: это простой пример. В моей реальной проблеме у меня есть несколько функций, таких как calcLength
, и они большие, я не хочу, чтобы компилятор встраивал их.
Примечание 2: я также открыт для разных подходов. В принципе, я хотел бы иметь решение, которое удовлетворяет этим требованиям:
- алгоритм указывается один раз (скорее всего, в шаблонной функции)
- если я укажу
1
какinc
, будет создана специальная функция, и код, скорее всего, будет векторизован - если
inc
не является константой времени компиляции, вызывается общая функция - в противном случае (константа времени компиляции, отличная от 1): не имеет значения, какая функция вызывается
constexpr
, передача константы времени компиляции ничего вам не даст. Однако вы можете сделать константу параметром шаблона, не являющимся типом. Тогда значение будет известно во время компиляции, и компилятор сможет соответствующим образом оптимизировать. - person NathanOliver   schedule 19.03.2019inc
, у него есть параметр шаблона типа. Но результат тот же. - person geza   schedule 19.03.2019template <std::size_t inc> float calcLength(const float *v, int size) { use inc here as a compile time value }
. - person NathanOliver   schedule 19.03.2019Constant<X>
используется какinc
. - person geza   schedule 19.03.2019inc
известен во время компиляции, это будет 1 99% времени. И, конечно, его можно оптимизировать намного лучше. У него огромная разница в скорости. - person geza   schedule 19.03.2019forceinline
функцию. Но я не хочу, потому что размер скомпилированного кода будет намного больше. Было бы ошибкой встроить эти функции в любую текущую архитектуру. - person geza   schedule 20.03.2019if constexpr
в своей проблеме, так что, наверное, нет. - person geza   schedule 20.03.2019inc
не константа времени компиляции, а значение1
, какую функцию следует вызвать? Ничего страшного, если это называетсяConstant<1>
версией? - person max66   schedule 20.03.2019__builtin_constant_p
- отличный инструмент для такого рода оптимизации. - person Marc Glisse   schedule 12.04.2019