Reputation: 4722
I'm in the progress of converting a piece of code from one geometric library to another. In my current code, I have a lot of specialized Point classes, and I'd rather have a single templated one. The new templated one, has an overloaded addition operator, defined as;
template<typename To>
Point<T, N> operator+(const Point<To,N>& p) const;
Where T
is the contained type, and N
is the dimensional arity of the point.
In order to provide the old usage interface, I had to subclass the Point class. Mainly by aliasing some members, and adding a few functions;
// Old library, could be indexed by var.x, ...
// New library, can only be indexed via. var[i]
int& x = data[0];
int& y = data[1];
int& z = data[2];
// Old library, supplied this function, new one didn't.
void subclass_function();
This works like a charm, and this replacement does it's job in most call-sites throughout the program. That is, unless there's an arithmetic operation, followed by a function provided by the compatibility class, say:
IntPoint3 index;
// The scalar multiplication results in the Point<int, 3>.
(index * 2).subclass_function();
Error: The Point<int, 3>
does not have the subclass_function()
defined.
What is the suggested solution to this? - (i.e. get the operator to return the subclass type)
Note1: I'd rather edit the Point class, than wrap all overloads of the arithmetic operators, in each specialized subclass.
Note2: The specialized subclasses doesn't add state.
Upvotes: 3
Views: 269
Reputation: 275585
Use the curiously repeating template pattern (CRTP).
The base template
class Point_impl
takes its derived type as an argument.
It returns the derived type from its operators.
template<class T, unsigned N, class D>
struct Point_impl {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D const*>(this); }
template<typename U, typename D2>
D operator+(Point_impl<U,N,D2> const& o) const {
auto retval = *self();
retval += o;
return retval;
}
};
Then your derived:
struct Bob:Point_impl<int,3,Bob>{
//...
};
etc.
I find static_assert
in self
with is_base_of
wise as well, as it catches some typos.
Upvotes: 1