Sign in to follow this  
irreversible

Templates & inheritance: why won't this compile?

Recommended Posts

The title says it all:

template<typename T>
struct IBaseVector	{
	__align16 union	{
		T c[4];

		struct	{
			T x, y, z, w;
			};
		};

	virtual IBaseVector<T>& operator=(const IBaseVector<T> & _vec)
		{
		c[0] = _vec.c[0];
		c[1] = _vec.c[1];
		c[2] = _vec.c[2];
		c[3] = _vec.c[3];

		return *this;
		}

	virtual IBaseVector<T>& operator*(const T & _v)
		{
		c[0] *= _v;
		c[1] *= _v;
		c[2] *= _v;

		return *this;
		}

	IBaseVector(T c0, T c1, T c2)
		{ c[0] = c0; c[1] = c1; c[2] = c2; c[3] = 0; }
};


struct IVector3D :
	public IBaseVector<float>	{

	IVector3D();
	};

IVector3D::IVector3D()
	: IBaseVector(10, 10, 10)
{
	
}

void TestFunc0()
{
	IVector3D v;

	v = v * 5.f; //<- link error: operator '=' is not defined (actually applies to operator '*')
}


Note that this is a test case and doesn't have to make sense.

Share this post


Link to post
Share on other sites
For the same reason that any assignment from a base class to a derived class will fail: a base class instance is not a derived class instance.

Share this post


Link to post
Share on other sites
SiCrane: makes no sense - I'm only accessing base class functionality guised as derived class stuff. Based on experience, I'm pretty sure this would work for non-templated classes (I haven't done a test build, mind you).

swiftcoder: unfortunately makes no difference - the link error is not related to this. Which is odd, because I would expect this omission to raise an alarm in the compiler...

PS - yes, I'm not too well versed with templates - I find them highly specialized and hardly ever see a pressing need to deal with them. This happens to be one such case, however.

Share this post


Link to post
Share on other sites
Try it:

struct Base {};
struct Derived : Base {};

int main(int, char **) {
Base b;
Derived d;
d = b;
}

Share this post


Link to post
Share on other sites
You don't need to use inheritance for what you're doing anyway, a simple typedef will do:
typedef IBaseVector<float> IVector3D;

Share this post


Link to post
Share on other sites
If you really don't want to use the typedef (and you should use the typedef), the CRTP can give you the behavior (or most of the behavior) you describe. (curiously repeating template pattern).

Note that your operator* is broken. You wrote operator*=, not operator*.

Note you skipped writing a copy constructor. Those are useful.

I tend to write a swap operator, a copy constructor, then implement operator= using the swap operator and copy constructor.

Share this post


Link to post
Share on other sites
Thanks for the replies! I know the code is faulty - I hadn't paid it much attention - I was just trying to work out why it wouldn't link.

As for using typedefs - unfortunately those are not enough since I'm writing SSE-accelerated single and double precision vector classes. Then again, using inheritance really gives me no real benefits either TBH.

I'd like to create a precision-swappable wrapper that would allow me to write two versions of the vector class code and change the type/precision at object initialization without writing more than one version of the external code. Doesn't seem there's an overtly easy way to do that, though.

Share this post


Link to post
Share on other sites
I'm confused. Why don't typedefs work?

If you want the code to deal with your vector as two different types of data, you either need to use run-time polymorphism or compile-time polymorphism.

Run-time polymorphism means you are accessing the data through virtual methods and the like.

Compile-time polymorphism requires that you recompile the code that is using your object when it uses a different type.

You can take the same code, and compile it for multiple types, and then have which one you are running be decided at run or compile time. This can be done through both of the above techniques.

Ie, imagine your extrernal code is "render a scene with a collection of vectors, using type P for the underlying floating point code". Then all of your external code is template code templated on either P or the type of the vector.

You then write a simple switch statement at some point that instantiates the double or float version of your engine depending on a run-time parameter.

You can even talk to external code bases that either provide both interfaces as run-time polymorphic choices, or expose a template implementation that you compile in both ways and pick which one.

These things are quite doable. They do require a reasonably deep understanding of the differences between run and compile time polymorphism, and some structural care to keep things sane.

...

For a concrete example that is somewhat tangental, imagine if you are writing a renderer.

You go off and implement multiple renderers, that use different technologies. All have the same external interface -- they just use different code internally.

When you are asked to render, you run a single switch statement at the start of the render, and pick which one you are running (or, you keep around a pointer to the correct renderer, and switch based on logic you decide upon at setup/startup time).

Some of the renderers might be using exactly the same code, but with different template parameters passed in. Other of the renderers might be utterly different implementations, use asm, or even some other language.

The renderers may differ from each other only by compile-time polymorphism. You pick which one you run via run-time polymorphism.

That make any sense at all?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this