Add member functions and member variables based on template argument
Asked Answered
V

2

7

I have a family of functions {f_n} where f_0 is continuous, f_1 is continuously differentiable, $f_{n} \in C^{n}[a,b]$ so on. I have a C++ class which gives a numerical evaluation of f_n via a lookup table on a vector v

template<int n, typename Real=double>
class f
{
public:
    f() { /* initialize v */ }

    Real operator()(Real x) { /* find appropriate index for x, and interpolate */}

private:
    std::vector<Real> v;
};

However, if f is differentiable (n >= 1), I want to add a member function:

template<int n, typename Real=double>
class f
{
public:
    f() { /* initialize v and dv */ }

    Real operator()(Real x) { /* find appropriate index for x, and interpolate on v */}

    Real prime(Real x) { /* find appropriate index for x, and interpolate on dv */}

private:
    std::vector<Real> v;
    std::vector<Real> dv;
};

I would also like to add a second derivative member for n >= 2, so on. Can this be done in a single class? (C++17 syntax is acceptable for me.)

Vidovik answered 1/3, 2019 at 20:53 Comment(3)
how do you inspect n to be larger or equal to 1? Is this supposed to be a non type template parameter?Reece
@GuillaumeRacicot: My bad, typo. Should've been int n.Vidovik
"Can this be done in a single class?" Well, no. You have a different class for each pair of template parameters. So inherently more than a single class. Did you mean a single (template) declaration?Cordova
C
5

For each n > 0, we add a new member function taking that value as an argument that inherits from the next level down:

template<int n, typename Real=double>
class f
    : public f<n-1, Real>
{
public:
    f() { /* initialize dv */ }

    using f<n-1, Real>::prime;
    Real prime(Real x, integral_constant<int, n>) { 
        /* find appropriate index for x, and interpolate on dv */
    }

protected:
    std::vector<Real> dv;
};

Where the base version adds the operator():

template<typename Real=double>
class f<0, Real>
{
public:
    f() { /* initialize v */ }

    Real operator()(Real x) { /* find appropriate index for x, and interpolate */}
    Real prime(Real x) { return (*this)(x); }

protected:
    std::vector<Real> v;
};

This means that the first derivative calls prime(x, integral_constant<int, 1>{}), the second derivative calls prime(x, integral_constant<int, 2>{}), etc.

Contamination answered 1/3, 2019 at 22:15 Comment(0)
L
1

You can simply have a template member function and a static_assert that ensures you are not taking a derivative that is not supported by your class. Eg:

template <int n, /* other stuff */>
class f
{
  /* Other stuff not shown */
  template <int p>
  Real prime(Real x)
  {
    static_assert(p <= n, "unsupported derivative");
    /* do whatever you need to to implement the pth derivative */
  }
};

Thus an object of type f<1> will support prime<1>() but not prime<2>(), etc. If you accidentally call prime<3> on an object of type f<1> the compiler will call you out on it. Up to you whether you want to think of prime<0> as identical to operator () or change your static_assert to include a check for p > 0.

Lil answered 6/3, 2019 at 21:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.