Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

Template Hell

Started by Nixsos 5 replies 900+ views
Original Post
Nixsos
Nixsos
I'm having difficulties with templates. Here's a little piece of code to illustrate my problem: Just to keep things simple i have created this small class

template<class T>
class Ptr
{
public:
	T *GetPointer() { return m_Ptr; }

private:
	T *m_Ptr;
};
Now i want to create a base class which looks like this:

class Base : public Ptr<Base>
{
public:
	void Start()
	{
		Foo();
	}

	virtual void Foo();
};
As you can see, the base class derives from the Ptr class. The pointer becomes a pointer to class Base. Now later on, i want to extend the base class:

class Specialized : public Base
{
public:
	void Foo();
};
Now it's time to create an instance of the derived class

Specialized S;
S.GetPointer()->Start();
Now the problem: I call the GetPointer method, which returns a pointer to a Base class, and NOT to the derived class. Which means that only Foo() in Base gets called and NOT Foo() in Derived, which i would like. How can i make it so, that the pointer changes from the Base class to the newly created derived class? I've already tryed to do it in a constructor, but that didn't work.

Derived():
    Base<Derived>()
{

}
Is this even possible?
antareus
antareus
Template the Base class (Base), and have Base derive from Ptr.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Nixsos
Nixsos
Quote:
Original post by antareus
Template the Base class (Base), and have Base derive from Ptr.


Yeah that was one of my ideas as well... is it possible to have a default argument like so:?

template<class T = Base>class Base : public Ptr<T>{};



This gives me an error while compiling.

This would be best, so that Base can be stand-alone as well, which is my goal here. I want to either derive from base, or use Base as-is...

What are my other options here?
Fruny
Fruny
How can i make it so, that the pointer changes from the Base class to the newly created derived class?

You can't.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Polymorphic OOP
Polymorphic OOP
My first question is, why does your object have a pointer to an instance of its own type to begin with? If that pointer is supposed to represent the this pointer of the derived object, then you are just wasting space in the object itself. Instead, just use the this pointer in Ptr and static_cast the pointer to a pointer to a derived. Unless you are using multiple inheritance where the leftmost hierarchy doesn't lead back to the Ptr template instantiation, that static_cast will [in most cases] have no runtime cost. You can then just get rid of the pointer datamember completely. If you honestly need the pointer there because it points to a different instance (which seems a little strange without more information), then the pointer datamember will have to remain.

Quote:
Original post by Fruny
How can i make it so, that the pointer changes from the Base class to the newly created derived class?

You can't.

Sure ya can, by templating the "Base" as well, and passing that parameter down to Ptr instead of the Base template instantiation, as was stated.

Quote:
Original post by Nixsos
I call the GetPointer method, which returns a pointer to a Base class, and NOT to the derived class. Which means that only Foo() in Base gets called and NOT Foo() in Derived, which i would like.

Well, right now you have Foo marked as virtual, so the proper function should be called anyways as long as you initialized the pointer properly. If you want to get rid of virtual, then, again, template "Base" and use the curiously recurring template pattern (passing the furthest child as a template parameter to Base).

Quote:
Original post by Nixsos
How can i make it so, that the pointer changes from the Base class to the newly created derived class?

The key is that you don't make the pointer type "change," you have it be the derived class from the beginning by basing the pointer type and/or the function return type off of the template parameter.

Quote:
Original post by Nixsos
This would be best, so that Base can be stand-alone as well, which is my goal here. I want to either derive from base, or use Base as-is...

Yeah, you, can. To do that, make a dummy type and have that be the default parameter for Base. Either use metaprogramming or explicitly specialize the template for when the Base template parameter is said dummy type -- have it pass its own type to Ptr as a tempalte parameter instead of Base's tempalte parameter in that case. Then, to just use Base without deriving from it, write Base<> for the type. If you want to get rid of the <> then what I suggest you'd do would be to call the template "DerivedBase" and typedef its default instantiation to Base. Example with metaprogramming solution (this is going back to my assumption in my first question to make the solution quicker to write out -- if my assumption in the first question was incorrect, then everything still applies, just that you have to initialize your pointer):

template<class T>class Ptr{public:  T *GetPointer() { return static_cast< T* >( this ); }};class DBDummyType;template< typename LeftType, typename RightType >struct is_same{  static const bool value = false;};template< typename Type >struct is_same< Type, Type >{  static const bool value = true;};template< bool Condition, typename PosResult, typename NegResult >struct ternary_c;template< typename PosResult, typename NegResult >struct ternary_c< true, PosResult, NegResult >{  typedef PosResult type;};template< typename PosResult, typename NegResult >struct ternary_c< false, PosResult, NegResult >{  typedef NegResult type;};template< typename Condition, typename PosResult, typename NegResult >struct ternary  : ternary_c< Condition::value, PosResult, NegResult >{};template< typename DerivedType = DBDummyType >class DerivedBase  : public Ptr< typename ternary< is_same< DerivedType, DBDummyType >                                , DerivedBase<>                                , DerivedType                                >::type              >{public:  void Start()  {    Foo();  }  virtual void Foo() {}};typedef DerivedBase<> Base; // So you never have to just type <>class Child  : public DerivedBase< Child >{};Child Test;  // Should workBase Test2;  // Should work


If you have boost installed, then just use mpl's if_ or if_c instead of my ternary and ternary_c, and the type_traits is_same instead of mine.

Going ever further, you can probably get rid of your virtual foo call as well -- instead of having it virtual, use the GetPointer() function to get a pointer to the instantiatied Child and call the Foo on it. This will work going as far down in the hierarchy as you are passing the Child type, so if you inherit from your example "Specialized" and don't make "Specialized" templated in a similar manner to Base, and you plan on altering the functionality of foo in Specialized's child, then virtual is necessary on the first non CRTP level (Base levels can remain non-virtual for optimization).

[Edited by - Polymorphic OOP on July 1, 2004 4:34:46 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.