I would like to write a template class along the lines of:
template <typename T>
struct lerp1d {
lerp1d(const T& abs_begin, const T& abs_end, const T& ord_begin, const T& ord_end) {}
auto operator()(val_t x) const -> val_t {
// ...
}
const std::vector<val_t> x_data_;
const std::vector<val_t> y_data_;
};
Such that I can ideally initialise instances like:
std::vector<double> x = /*...*/;
std::vector<double> y = /*...*/;
double *x = get_arr_x();
double *y = get_arr_y();
auto l1 = lerp1d(x.cbegin(), x.cend(), y.cbegin(), y.cend()); /* (1) */
auto l2 = lerp1d(x, x n, y, y n); /* (2) */
The question is, how to alias the val_t
?
One option would be to simple say:
using val_t = typename T::value_type;
But that does not work with instance (2)
. Tried std::enable_if
or std::conditional
with std::remove_pointer<T>
and std::is_pointer_v<T>
, but does not seem to be applicable.
CodePudding user response:
The way you've designed it, if you provide two different types of collection having the same value_t
, it will produce two different classes where there is no points of them being different, except to construct them.
E.g. in (1), you would build a lerp1d<std::vector<double>::iterator>
and in (2) a lerp1d<double*>
. But you're ontly interested in the double
part, not the vector or the pointer.
I would advise to template the class on the type you're actually storing and create another template for the constructors on the iterator type.
#include <vector>
template <typename T>
struct lerp1d {
template<typename U>
lerp1d(const U& abs_begin, const U& abs_end, const U& ord_begin, const U& ord_end)
: x_data_(abs_begin, abs_end), y_data_(ord_begin, ord_end)
{}
auto operator()(T x) const -> T {
return x; // to be implemented
}
const std::vector<T> x_data_;
const std::vector<T> y_data_;
};
static double xs[] = {3.2, 5.1, 4.8};
static double ys[] = {7.3, 5.3, 1.0};
int main(void) {
std::vector<double> vx = {3.2, 5.1, 4.8};
std::vector<double> vy = {7.3, 5.3, 1.0};
double *x = xs;
double *y = ys;
auto l1 = lerp1d<double>(vx.cbegin(), vx.cend(), vy.cbegin(), vy.cend()); /* (1) */
auto l2 = lerp1d<double>(x, x 3, y, y 3); /* (2) */
}
CodePudding user response:
You can use std::iter_value_t
to get the value_type
of the iterator in C 20
#include <iterator>
template<std::random_access_iterator T>
struct lerp1d {
using val_t = std::iter_value_t<T>;
lerp1d(const T& abs_begin, const T& abs_end,
const T& ord_begin, const T& ord_end) {}
auto operator()(val_t x) const -> val_t {
// ...
}
const std::vector<val_t> x_data_;
const std::vector<val_t> y_data_;
};