Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic data type choosing based on template

Tags:

c++

templates

suppose I have an object like this:

class Spline {
public:
    Spline(std::size_t const dim);
    // Quite a few functions here. One of those:
    vec operator()(double const t) const; // Returns vector of dimension d
}

Now, at most uses of this class, the dimension will already be determined at compile time, thus it would be a good idea (for performance reasons) to change the class like this:

template <std::size_t dim>
class Spline {
public:
    Spline();
    // Quite a few functions here. One of those:
    vec::fixed<dim> operator()(double const t) const; // Returns vector of dimension d
}

(For those who wonder, vec and vec::fixed are objects defined by the armadillo linear algebra library). Now I would like to have both versions living in parallel, thus being able to choose the dimension at compile time as well as during runtime. In short, I would like to create the equivalent of vec::fixed<dim> as Spline::fixed<dim>, but without implementing all functions twice. Especially, I would have to choose the return type of all those functions depending on whether there is a template argument present or not.

Do you have any idea how I might accomplish this, especially thinking in terms of a clear and maintainable design? (In the hope that I made myself clear, which I am not totally sure about.)

like image 493
Thilo Avatar asked May 25 '26 07:05

Thilo


1 Answers

Use a simple traits metastruct and specialize that.

template<std::size_t dim>
struct spline_return_traits{
  typedef vec::fixed<dim> type;
};

template<>
struct spline_return_traits<0>{ // 0 is a special marker for runtime dimensions
  typedef vec type;
};

template<std::size_t dim>
class Spline_impl{
  typedef typename spline_return_traits<dim>::type spline_return;
public:
  spline_return operator()(double const t) const;
// if <dim> is 0, then the dynamic vec will be chosen as the return type
  // all your functions
};

class Spline : public Spline_impl<0>{ // default is dynamic
public:
  template<int dim>
  struct fixed : public Spline_impl<dim>{
  };
};

Now you simple use that. :) Every operator, constructor and function of Spline_impl should be available in the subclasses. For the implementation of each function, you need to do some branching where it's a must to decide between runtime or fixed vec:

if(dim == 0){
  // runtime specific stuff
}else{
  // compile-time specific stuff
}

Use as:

Spline dynamic_spline;
Spline::fixed<10> fixed_10_spline;

Only problem being that the Spline class will be double the size of Spline_impl... :/ Lemme think if I can find a solution to that too.
Edit: If you don't want Spline to be double the size of Spline_impl, one possibility is to add a little verbosity and a typedef:

class Spline : public Spline_impl<0>{ // default is dynamic size
public:
  template<std::size_t dim>
  struct fixed{
    typedef Spline_impl<dim> type;
  };
};

And use as

Spline dynamic_spline;
typename Spline::fixed<10>::type fixed_10_spline;
like image 111
Xeo Avatar answered May 26 '26 19:05

Xeo