Topic: templated virtual functions
Author: nospam@nospamdavid.nospam.gordon.nospamname (David Gordon)
Date: Mon, 15 Mar 2004 18:36:48 +0000 (UTC) Raw View
Hi Folks,
I'm aware that the standard forbids virtual functions from being
templated, and I appreciate the reasons why. In short, a templated
virtual function would need to be defined at compile time for every
possible type, a theoretically infinite number.
I only came to realise this recently, after basing an otherwise elegant
design on this flawed principle. My workaround has been to do precisely
what we want to avoid by using generic programming - defining one
function per type. But I'm left wondering if there wouldn't be a neater
solution, or possibly an addition to the standard allowing a limited
range of templates to be defined for a virtual function.
Here's some code to illustrate my situation. I have some code which
works with rotations in a variety of formats. I want to be able to pass
between formats using implicit casting, and provide a polymorphic type
which can represent any rotation. I want to ensure that when conversions
occur, they are as direct as possible, i.e. if a conversion from euler
to euler is requested, a reference is simply passed through.
Here's my code as it stands:
struct JointBase
{
virtual ~JointBase() {}
virtual euler GetEuler()const = 0;
virtual quat GetQuat()const = 0;
virtual matrix GetMatrix()const = 0;
virtual void SetRotation(const euler&) = 0;
virtual void SetRotation(const quat&) = 0;
virtual void SetRotation(const matrix&) = 0;
};
template <typename _Rot>
struct RotationTraits
{
// a traits object defined to expose is_euler, is_quat, is_matrix
}
template <typename _Rot>
struct Joint : public JointBase
{
template <typename _OtherRot>
Joint(const Joint<_OtherRot>& j)
{
typedef RotationTraits<_Rot> rt;
if (rt::is_euler) SetRotation(j.GetEuler());
else if (rt::is_quat) SetRotation(j.GetQuat());
else if (rt::is_matrix) SetRotation(j.GetMatrix());
}
virtual euler GetEuler()const { return rotation; }
virtual quat GetQuat()const { return rotation; }
virtual matrix GetMatrix()const { return rotation; }
virtual void SetRotation(const euler& e) { rotation = e; }
virtual void SetRotation(const quat& q) { rotation = q; }
virtual void SetRotation(const matrix& m) { rotation = m; }
_Rot rotation;
};
This is pretty quick. In the above example, SetRotation doesn't need to
be virtual (but it does in my actual code) and optimised copy
constructors should be made for the different templated cases. It would
be nice to have pass-by-reference happen in cases where Get*() is
returning the class's own type.
What I'd like to be able to write is something like:
struct JointBase
{
virtual ~JointBase() {}
template <typename _Rot = euler, quat, matrix> // bad syntax idea
virtual _Rot GetRotation()const = 0;
template <typename _Rot = euler, quat, matrix>
void SetRotation(const _Rot&) = 0;
};
template <typename _Rot>
struct Joint : public JointBase
{
template <typename _OtherRot>
Joint(const Joint<_OtherRot>& j)
{
rotation = j.GetRotation<_Rot>();
}
template <typename _OtherRot>
virtual _OtherRot GetRotation()const { return rotation; }
template <typename _OtherRot>
virtual void SetRotation(const _OtherRot& e) { rotation = e; }
_Rot rotation;
};
I hope this is clear.. any ideas?
Thanks,
David
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]