Advertisement

Templates & Inheritance

Started by November 08, 2000 08:52 PM
9 comments, last by Shannon Barber 24 years, 2 months ago
Is there a way to ensure that a parameter passed to a template is derived from a particular base class? (at compile time)
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
There is no langage construct in C++ that directly forces such a relationship.

However, you could hack it. One way is to give the particular base class has some unique function and have the template class call it. Then resist the temptation, if necessary, to add that function to other classes as well.

Example:

  class A {public:  void silly_hack_to_ensure_derivation() {#if DEBUG    volatile int x = 5;#endif  }};  class B : public A { };class C { };  template <class T> class MyTempl {private:  void check_silly_hack_to_ensure_derivation() {#if DEBUG      T x;    x.silly_hack_to_ensure_derivation();#endif   }  // ... rest of template class ...};    MyTempl<B> B_templ;   //will compileMyTempl<C> C_templ;   //won''t compile    



This is just a silly trick. I haven''t tested it myself, so you may need to play around with it a bit to get it working.

For instance, I''ve surrounded some things with DEBUG, to make sure release code doesn''t have any extra weight, but you need to make sure that even in DEBUG mode it doesn''t get thrown out (which is unlikely in debug builds, but possible if a compiler is being stupid).

Also note that my quick hack above requires a default constructor for your class, which may not be acceptable. So you''d have to tweak it a bit to get things working. What might make it nicer is if the silly_hack function was a static member of A. I''d say private and make the template class a friend of A, but I don''t know whether you can have template friends.

---- --- -- -
Blue programmer needs food badly. Blue programmer is about to die!
---- --- -- -
New York. New York. New York. Texas. Texas. New York. New York. Canada.
---- --- -- -
Advertisement
Use RTTI, basically do a dynamic_cast to the type you want. If the pointer is null then the type you are pointing to cannot be cast to the type you are wanting.
Keys to success: Ability, ambition and opportunity.
That of course works at runtime, not compile time. Practically speaking if the template trying an operation against the data type it is instantiated with that can''t be done then the compiler won''t compile it. You have to remember that templates are just elborate macros. They generate code and that code has to compile. I have a bit of trouble picturing on a practical basis where the generated code would be syntaxically correct but symantically wrong except for just coincidences in member function names. Most cases I can think of are ones where a template is not the right solution such as using a template where a polymorphic class is the correct solution. Perhaps a bit more detail would help me understand.
Keys to success: Ability, ambition and opportunity.
quote:
You have to remember that templates are just elborate macros


They''re a lot more than just elaborate macros

There is another way to do this that doesn''t involve changing any of the existing class, and at compile time. Here''s an example:

template<class TBase, class T>class IsKindOf{private:	struct Yes{char c[10];};	struct No{char c;};	static Yes TestFunc(TBase*);	static No TestFunc(...);public:	enum 	{		RET = (sizeof(TestFunc(static_cast<T*>(0)) ) == sizeof(Yes))	};	};struct Base {};struct Sub : Base{};int main (){	cout << IsKindOf<Base, Sub>::RET << endl; // Output is 1	cout << IsKindOf<Base, int>::RET << endl; // Output is 0	return 0;   } 


The reason this works is that when you use sizeof on a function, your actually using it on the return type. And since sizeof happens at compile time, you can use the result of it initialise compile time constants (such as enums). The functions are never really called, so they don''t need a body. Also because none of this is ever used at runtime, your left with an enum of 0 or 1. So you don''t get any speed hit from using it.

You could use this kind of thing to generate a compile time error when the types aren''t valid, you''d need an extra template class to do this though. Something like this should work:

template<bool Check> struct compile_time_check{ 	int compile_time_check_failed[Check ? 1 : -1]; };template<> struct compile_time_check<true> {};int main (){	compile_time_check<IsKindOf<Base, Sub>::RET> check1; // Fine	compile_time_check<IsKindOf<Base, int>::RET> check2; // Compile error		return 0;   } 
quote: Original post by Magmai Kai Holmlor
Is there a way to ensure that a parameter passed to a template is derived from a particular base class? (at compile time)


You can do something like this:

class Base
{};

class Derived : public Base
{};

class NotDerived
{};

template < class T >
class MyTemplate
{
public:
MyTemplate()
{
T *tptr;
Base *bptr = tptr;
}
};

MyTemplate < Derived > derived; //This will work
MyTemplate < NotDerived > notDerived; //This will generate a compile-time error (cannot convert NotDerived* to Base*)


Jason


Edited by - shankel on November 9, 2000 3:11:43 PM

Edited by - shankel on November 9, 2000 3:12:54 PM

Edited by - shankel on November 9, 2000 3:13:55 PM
Jason ShankelMaxis/EA
Advertisement
Yeah I guess that was a silly question...
It would be highly unlikely to have a non-derived class mimic the interface of a derived class...

I guess what I really meant to ask, is how to communicate what the base class is...

  //I want the class passed in to be derived from CPacketHandlertemplate<class TPacketHandler>class CNetworkServer{//...TPacketHandler m_ServerPacketHandler;};//I was trying to avoid something like this//base->derivedclassclass CNetworkServer{public:CNetworkserver(CPacketHandler*);private:CPacketHandler* m_lpServerPacketHandler;}  
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Are you just wanting to avoid the pointer? It seems a cumbersome syntax to use templates just to avoid using a pointer. If you are worried about the calling function deleting it then make a copy of it. Pass it by referance and they don''t have to do a new, they can just allocate it on the stack, pass it to you and discard it. If it is allocating something that can''t be allocated twice then delay that. Have the constructor call a function to actually do the allocation. Just how big is this structure?
Keys to success: Ability, ambition and opportunity.
It was late, I was tired. I should have viewed it from the perspective of trying to make it as simple and idiot-proof as possible for other programmers. I should also assume you don''t want to get into all the gory details. If just in the constructor on the template CPacketHandler *lpPacketTest = &m_ServerPacketHandler; then you will get a compiler error if TPacketHandler is not derived from CPacketHandler.

I don''t know much about networks, but wouldn''t you want the server to have a list of packet handlers that it checks packets against for a match? Then when it finds a match dispatch the packet against that handler. Do I misunderstand what the server and packet represent? I''m assuming the server abstracts the actual network calls while the packet handlers handle breaking up the stream logically and distributing it to the appropriate code much like an event loop in a program.
Keys to success: Ability, ambition and opportunity.
The server receives packets and validates them; it then calls the TPacketHandler, telling it the packet type, and gives it a pointer to the payload.

TPacketHandler processes the payload (based on the packet type) and sends relevent data to the game engine.

This way I can use the same NetworkServer code with different packet manipulators, and more importantly, use the same packethandler with different types of networks... (IP, IPX, Serial, ...)

...
thanks, i didn''t think of that (*lpPackerHandler = &...)
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement