Home > Net >  Define a type alias in C templates conditionally on template arguments
Define a type alias in C templates conditionally on template arguments

Time:07-31

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_;
};

Demo

  • Related