У меня есть функция, которая вычисляет первую производную dy/dx для дискретных значений y(x), построенных как std::vector:
vector<double> CalcDerivative(vector<double>&y, vector<double>&x) {...}
Часто интервал dx является постоянным, поэтому было бы эффективнее передать этой функции значение типа double вместо vector<double> в качестве аргумента x.
Я попытался сделать это с помощью std::variant. Однако недостатком std::variant является то, что он не может обрабатывать ссылки, поэтому вектор x должен быть скопирован при передаче в функцию как вариант.
На данный момент я решил проблему, определив две функции с перегруженными аргументами. Но мне интересно, есть ли более элегантное решение, которое не будет дублировать код для двух случаев (x как double или как vector<double>).
Либо передайте значение 1 также как vector
и проверьте if (x.size() == 1)
, либо сделайте аргумент x
шаблоном, а затем проверьте if constexpr
, это double
всегда используйте это, а если нет, используйте индекс массива.
Независимо от того, какое решение вы придумаете, функция, принимающая вектор с одним значением, все равно должна работать. Не отнимайте у пользователя функционал, если он хочет передать вам вектор одного значения.
Одним из возможных решений может быть определение «рабочей» функции таким образом, чтобы она не зависела от «количества переданных двойников». Для этой цели подойдет std::span
. Примерное решение может выглядеть так:
std::vector<double> CalcDWorker(
std::span<const double> y, std::span<const double> x)
{
... // x.size() == 1 indicates uniform spacing
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, const std::vector<double>& x)
{
return CaclDWorker({y.begin(), y.end()}, {x.begin(), x.end()});
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, double x)
{
return CaclDWorker({y.begin(), y.end()}, {&x, 1});
}
Для этого требуется C++20, но есть сторонние span
реализации, доступные и для более ранних версий C++ (например, предоставленная Boost).
Живая демонстрация: https://godbolt.org/z/n6adEKWes
Лично я бы сказал, что перегрузка — это довольно элегантное (и, безусловно, читабельное) решение. Чтобы избежать дублирования кода, извлеките метод для общих частей (вы не предоставили код, поэтому я не могу быть более конкретным). Кроме того, в копировании данных нет ничего плохого. Не делайте преждевременных оптимизаций.