Archived

This topic is now archived and is closed to further replies.

neonfaktory

2 Layer Template Structures Useless?

Recommended Posts

So I have my GUI design figured out. I use my standard Linked List class that I''ve been using for the rest of my program to hold my master list of GUI elements. It is obviously templated. However, my GUI class is also templated. Like I''m sure others have done, all the buttons and textboxes are "windows" but with different aspects to them. 1 scroll bar on the screen might be altering an "int" while another might be altering a "float". The natural solution is to make the GUI class templated. But there''s the problem. Upon declaration of the master gui list "GUILIST" that keeps track of all the elements, it requires you to define what type of template the actual GUI elements in that list will be... defeating the purpose of having them templated if they all have to be the same type anyway. Soo, am I doing this wrong? Can I have a templated Linked List class that holds differently templated GUI elements? Thanks for any help

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
don''t make the GUI class templated. Just derrive from a base class and store pointers.

Share this post


Link to post
Share on other sites
... That''s pretty general. "store pointers"? Pointers to what? The values the GUI elements are changing? If so, that is why the class is templated because those values could be the "int"s I store ammo with or the "float"s I use to store weapon-specific percentages with.

Besides, thats not the main point of the post. Can you have a templated class use another templated class as a template without "fixing" the enclosed template to a specific datatype? Thanks again for any help

Share this post


Link to post
Share on other sites
Yep, a GUI system is actually a perfect candidate for a polymorphic inheritance tree. Ie. you have a CDialog base class, with standard control and event management functionality (mostly implemented by virtual functions). From that base class, you derive your individual controls:

class CDialog { /* base class functionality */ }

class CButton : public CDialog { /* ... */ }

class CDropdown : public CListbox, CButton { /* ... */ }

class CSpecialDropdown : public CDropdown { /* ... */ }

etc...

About your approach: well, I don't knwo your details, but it sounds like you're abusing the template feature. If you wanted a float/int Scrollbar, then simply template the derived type:

template <class T> CScrollbar : public CWhatever { /* ... */ }


[edited by - Yann L on May 7, 2003 6:03:20 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by neonfaktory
Besides, thats not the main point of the post. Can you have a templated class use another templated class as a template without "fixing" the enclosed template to a specific datatype? Thanks again for any help


Short answer? No.

Share this post


Link to post
Share on other sites
To Yann:
What you mentioned is exactly what I'm doing, "template CScrollbar : public CWhatever" more or less. The problem arises when I want to create a Linked List of them. The Linked List class itself is templated, and when I try to make a list of the templated "CScrollbar" class with the already templated "LinkList" class, it asks to know what template the "CScrollbar" class will be upon declaration, instead of leaving it open to determine later, defeating the whole point of making the CScrollbar class templated...

Is there any way to work around this?

[edited by - neonfaktory on May 7, 2003 12:04:21 AM]

Share this post


Link to post
Share on other sites
Your linked list should be a list of pointers to your common base GUI class. The fact that the derived classes (such as scrollbars etc) are templated makes no difference.



[ MSVC Fixes | STL Docs | SDL | Game AI | Sockets | C++ Faq Lite | Boost
Asking Questions | Organising code files | My stuff | Tiny XML | STLPort]

Share this post


Link to post
Share on other sites
quote:
Can you have a templated class use another templated class as a template without "fixing" the enclosed template to a specific datatype?
Yes, of course.
  template<typename T>
class SomeClass {
};

template<template<typename> class K>
class SomeOtherClass {
public:
typedef K<int> whatever;
};

int main()
{
typedef SomeOtherClass<SomeClass>::whatever whatever;
}
This should be mentioned in any good C++ book.

- lmov

Share this post


Link to post
Share on other sites
Well, maybe this will clear it up some, because I didn't think what I was doing was that complicated...

          
template<class itemType>
class CList // My Linked List Class - Works Fine

...
template<class itemType>
class GUI // My Gernerac GUI Class

...

// Then I simply want to be able to say:

CList<GUI> GUILIST; // <--- Doesn't work, says "GUI" needs a class type


// So I can do:

GUILIST.Add(new GUI(...)); // And pass ints/floats/etc. to the GUI constructor


// ^^^ All this does not work.

// The line that declares "GUILIST" gives an error about "GUI" needing a class type, as in...


CList<GUI<type>> GUILIST; // <--- Doesn't work either (bad syntax)



Whatever the syntax is, it defeats the purpose of me being able to add GUIs with different templated types to the GUILIST... Gah!

*EDIT* Code Examples needed source tags

[edited by - neonfaktory on May 8, 2003 11:00:42 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
hold a list of pointers

Share this post


Link to post
Share on other sites
... AP, that's what my Linked List is. Pointer to Object, Pointer to Previous Object, and Pointer to Next Object, templated so it can be used to make lists of different types. I figure that should be assumed in a Linked List, not to mention it doesn't solve the problem at hand.

[edited by - neonfaktory on May 8, 2003 12:06:14 PM]

Share this post


Link to post
Share on other sites
Templates are compile-time, and inheritance is run-time. If you want to have your GUI types vary at run-time, you must create an inheritance hierarchy.

First, define an abstract base class (not a class template!) that acts as a standard "interface" of common commands to all GUI elements:


  
namespace gui {

class element {

// construction


public:
element () : its_parent (0),
its_children (),
its_identifier (get_new_guid ()) {}

// destruction


public:
virtual ~element () { remove_self_from_parent_and_child_lists (); }

// methods


public:
virtual void on_draw () = 0;
virtual void on_left_click () = 0;
virtual void on_right_click () = 0;

element* parent ();
element* child (int identifier);

// data


private:
element* its_parent;
list <element*> its_children;
int its_identifier;
};
}


Now you can derive any classes from gui::element and add them to the list:


  
namespace gui {

// ...


template <class T>
class templated_element : public element {

// construction


public:
templated_element (const T& value = T ())
: its_value (value) {}

// methods


public:
void on_draw () { output_to_screen (its_value) }
void on_left_click () { ++ its_value; }
void on_right_click () { -- its_value; }

// data


private:
T its_value;
};
}


And because all GUI elements are derived from the abstract class GUI::element, they all sport the same interface:


  
int main ()
{
// create a new templated gui element using the reguler element interface


gui::element* p = new gui::templated_element <char> (''x'');

// simulate two mouse button clicks


p->on_left_click ();
p->on_left_click ();

// simulate a draw command


p->on_draw ();

// destroy the template gui element


delete p;
}


Basically, this inheritance hierarchy enables you to only specify the template parameters when you create a new element. Any new templated elements can then be used interchangably because they all support the same gui::element interface.

To implement a whole GUI in C++, you would probably have to create several more abstract interface classes like scrollbar, framewindow, etc. from which you will derive templated variants.

Share this post


Link to post
Share on other sites
Hmm...
So I would make a base class "class GUIobject" with all my standard functions... Then inherit a templated "GUItemplated" class... and then make GUILIST with the "GUIobject" base class and add objects using polymorphism by going "GUILIST.Add(new GUItemplated(...))"? Just to generalize the concept because your code looked a little wacky to me (ex. I''ve never used "namespace" :O). Thanks for everyone''s help so far

Share this post


Link to post
Share on other sites
quote:
Hmm...
So I would make a base class "class GUIobject" with all my standard functions... Then inherit a templated "GUItemplated" class... and then make GUILIST with the "GUIobject" base class and add objects using polymorphism by going "GUILIST.Add(new GUItemplated(...))"? Just to generalize the concept because your code looked a little wacky to me (ex. I''ve never used "namespace" :O). Thanks for everyone''s help so far


Yes, you have the right idea.

Good Luck!

Share this post


Link to post
Share on other sites
*** UPDATE ***

Ok, this have been pretty much successful up till now. The last step, of course, is the one that breaks it all.

I'm using "GUI" as the base class to use with the GUILIST declaration and then adding "GUIT" elements to GUILIST instead, by using polymorphism. The goal was that different GUI elements in the GUILIST could be tied to different datatypes, the whole point of making the GUI elements templated. Here's some of my excellent codes; this is all in my GUI header file.


        
#ifndef _GUI_H_
#define _GUI_H_
// Inside GUI.h

...

enum eGUITYPE {GUIwindow, GUItext, GUIchgbar, GUIaccept, GUIclose};

// Base Class that CList will use for Master GUI List

class GUI
{
public:
// Con/Destructors //

GUI();
~GUI();

virtual void SetBounds(int x1, int y1, int x2, int y2) = 0;
virtual void Draw() = 0;

// Needed by CList //

GUI* GetNext(void) { return m_Next; }
GUI* GetPrev(void) { return m_Prev; }
void SetNext(GUI* T) { m_Next = T; }
void SetPrev(GUI* T) { m_Prev = T; }

private:
unsigned int X1, Y1, X2, Y2;
eGUITYPE myTYPE;

// Needed by CList //

GUI* m_Next;
GUI* m_Prev;
};

// Abstracted Class (w/ polymorphism) so elements can be templated

template <class itemType>
class GUIT : public GUI
{
public:
GUIT(eGUITYPE type, itemType* original, itemType min, itemType max);
~GUIT();

void SetBounds(int x1, int y1, int x2, int y2);
void Draw();

private:
itemType* ORIGINAL; // Pointer to the Original Value

itemType local; // Local Value to be copied back upon acceptance

itemType MINIMUM; // Minimum Value Available

itemType MAXIMUM; // Maximum Value Available

};

// EXTERNAL DECLARATIONS //

// Anything Including GUI will have access to these:

extern CList<GUI> GUILIST;// List of Open GUI Objects

...

#endif

//----------//

// Inside GUI.cpp

// EXTERNAL IMPLEMENTATIONS //

CList<GUI> GUILIST;

...

// IN THE MAIN CPP (THE PROBLEM) //

GUILIST.Add(new GUIT<unsigned int>(GUIchgbar, &UNIVSIZE, 1000, 2000));

(UNIVSIZE is just a global unsigned int test value in the main program). Here is the error I get when I uncomment that last line:

...error LNK2001: unresolved external symbol "public: __thiscall GUIT::GUIT(enum eGUITYPE,unsigned int *,unsigned int,unsigned int)" (??0?$GUIT@I@@QAE@W4eGUITYPE@@PAIII@Z)... : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

Any idea from those bits what the problem might be? It's prolly something dumb I missed... but thanks for any help you can provide!

[edited by - neonfaktory on May 21, 2003 3:30:43 PM]

Share this post


Link to post
Share on other sites
templated member functions definitions(not just declarations) need to be visible when the class is defined. So put them in the header.

Share this post


Link to post
Share on other sites
Could you elaborate please? I took a guess at what you meant and moved the actual definition/implmentation of "SetBounds" for the GUIT class from the cpp to the header, but that didn''t change anything. I assume I''m just not understanding what you mean - could you be more specific? Or maybe explain how it applies to my code? Thanks again

Share this post


Link to post
Share on other sites
Linker errors are generally not that bad. You might''ve defined your function slightly different from the way that you declared it, or perhaps you are missing other templates and the linker is just giving you a seemingly unrelated error message. (Compilers are famous for that, you know.) From the error message it seems that the linker cannot tell whether your constructor GUIT::GUIT (...) is defined.

Share this post


Link to post
Share on other sites
Thanks for the response NULL, I''m trying my damnest to figure it out.

In the meantime, I have a quick question that may help solve my problem.

Using "template class CList" and "template class GUI", what IS the proper syntax to make a CList of GUI elements?? I haven''t actually been able to get that to work - thanks again.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Like this:


CList<GUI<int> >


Note the space between the last two greater-than characters. This is so the compiler doesn''t think you''re trying to right-shift something.

-W

Share this post


Link to post
Share on other sites
Ahhh, thanks AP - I kept getting wacky errors and now I see why. I take it there''s no way to leave the inner datatype open till later without all this polymorphism I can''t get working?

Share this post


Link to post
Share on other sites