Click to See Complete Forum and Search --> : template won't compile - C2975


Amn
September 27th, 2002, 09:25 AM
Why doesn't Microsoft Visual C++ 7.0 want to compile this template:

template<char* p> class A
{
public:

char* f() { return p; }
};

A<"helo"> obj;


I get compiler error C2975 which briefly states that template needs a constant parameter for instantiation. Now, isnt "helo" a const design-time evaluated entity ?

I consider this another one of the "yet unimplemented" template features...sucks :(

has any of you come across c2975 before ?

Thanks,
Amn.

Yves M
September 27th, 2002, 10:04 AM
This is a very strange use of templates... You use them for classes or types, but not for constant strings...

What you are trying to do is better done with a non-templated class that has a constructor that takes a char *...

Amn
September 27th, 2002, 10:07 AM
Well, this is just an example which points out that MSVC++ 7.0 doesnt treat "helo" as a constant, or gives C2975 error nevertheless.

If you need a justfiyment for the use of constant strings for templates here is one:

template<LPCTSTR strClassName>
class win32window
{
public:

HWND create(...)
{ return ::CreateWindow(strClassName, ...); }
};

Like that, simple wrapper for system defined window classes.

BUt no, MSVC++ wont compile this..

Thanks for reply anyway... do you know if the error is a bug or what ?

Graham
September 27th, 2002, 10:07 AM
You can't use a string literal as the argument to a char* template parameter. Sorry, but that's the standard.

char hi[] = "hello";

A<hi> obj;

should work, IIRC.

Graham
September 27th, 2002, 10:08 AM
Just seen your reply to Yves. You can't blame Micro$oft, this time, I'm afraid - the complier is correct to reject your code.

Amn
September 27th, 2002, 10:09 AM
Hmm, any is this because of the stack placement in case of "helo" and data segment placement in case of hi[] ? Otherwise i dont know why i can use the constant hi[] and cannot use constant "helo". Can you please refer me to a standard article pointing the issue out ?

Thanks,

PaulWendt
September 27th, 2002, 10:11 AM
Your question was already answered a few days ago:

http://www.codeguru.com/forum/showthread.php?s=&threadid=210848

Edit: I guess a few people replied before me. I also want to point
out that Paul McKenzie quoted some relevant material from the
standard.

--Paul

Amn
September 27th, 2002, 10:14 AM
Thanks A LOT everyone. a true help is given to me ;)

Reading the standard now... guess this is exactly because stack unwinding of literals prevents correct template class operation...

Yves M
September 27th, 2002, 10:36 AM
If you need a justfiyment for the use of constant strings for templates here is one:

template<LPCTSTR strClassName>
class win32window


Interesting, I'll go to bed less stupid today ;)

Amn
September 27th, 2002, 10:38 AM
Why do you think it is a stupid approach ? =]

* Just speaking between us two (and the rest of the community)*

Graham
September 27th, 2002, 10:43 AM
Originally posted by PaulWendt
Your question was already answered a few days ago:

http://www.codeguru.com/forum/showthread.php?s=&threadid=210848

Edit: I guess a few people replied before me. I also want to point
out that Paul McKenzie quoted some relevant material from the
standard.

--Paul

I would have sworn that I read that thread on comp.lang.c++.moderated, or I'd have looked for and quoted it myself. Thanks, Paul.

Yves M
September 27th, 2002, 11:22 AM
Originally posted by Amn
Why do you think it is a stupid approach ? =]

* Just speaking between us two (and the rest of the community)*

No no, what I meant was that this seems like a valid use of templates ;)

Although I'm still not quite sure that it's really useful to put constants into template parameters. I mean, writing a template based class is not the nicest thing as you can't program with .cpp files and have to implement everything in the .h file (with current compilers). If all I had to use were a constant as template parameter, I would prefer to use a constructor with a parameter instead.

The most compelling reason for me to avoid uneccessary templates is that intellisense for VC doesn't work in h files :/

Amn
September 27th, 2002, 11:39 AM
OMG, i read your comment as "i ll go to BE less stupid today", something that made me go questionmarks ;) funny, i read it again only now and realised it...OMG OMG OMG OMG ;)

sorry man ;)

Well of course nobody would use templates if a constructor parameter option is available instead hihi...it was a dumb example of me LOL

But i guess it could be useful to use window class templates to describe already defined WNDCLASSEX structures, which are stored in internal Windows registries. I mean

window<"EDIT">
window<"MDIClient">
window<"TREE">
window<"RICHEDIT">

etc.

Because since GUI is advancing so fast these days, and new controls appear all the time, it is a better thing to do then having to create a new class derived from window just to change classname parameter in constructor/create routine.


Thanks for your help once again,
and thanks everybody else on the message board who helped me out with the template thingie :)

Yves M
September 27th, 2002, 11:48 AM
what I meant is that you would use
pwindow = new window("EDIT");
pwindow = new window("RICHEDIT");

etc... instead of the template parameter

Amn
September 27th, 2002, 11:57 AM
Yes i considered that an option.

If you are willing to discuss this topic further before we are closed, i can say following:

It is a part of my framework which is supposed to be very thin layer over win32. And i earlier discarded that option "pWindow = new window("EDIT")", not because it is bad or something, in fact it is very straightforward, but the goal is to somehow blend win32 naked API and C++ OO design. It is a tough thing to do, since win32 suggests window classes ARE objects (run-time memory structures), and C++ does treat classes as objects only when a programmer designs them, and only basic RTTI is available. Again, Win32 allows individual windows to branch off their class behavior by means of SUBCLASSING, something that a C++ class would strongly object
since class member are not properties of its objects but simply functions which take a "this" pointer under the hood.

So basically i will break my head little longer than expected, but in the end if the idea of blending C++ and Win32 turns out to be NUTS, i will go for the constructor style approach as you suggested.

Yves, please note that I specifically write this framework to blend Win32 and C++, because this will allow developers to think native language OO design, and less handles and subclassing (which in C++ is inheritance). I do not say "forget Win32 API", but since we are programming in C++, which saves time, this whole thing might be good to do.

Anyway, i know i am a blabbermouth, but i hope someone will benefit from this.

Yves M
September 27th, 2002, 12:10 PM
Sounds like an interesting project. I'm not sure if you are aware of (you probably are), but you can have a look at the way WTL is structured. It is a very lightweight wrapper for some windows. Of course it's only part of the story though.

But I don't see why "pWindow = new window("EDIT")" is not C++ or not OO ?

I mean that window is actually a class that you define along the lines of :


class window
{
public:
window()
{
// Default constructor doesn't subclass
}
window(char *pSuperClass)
{
// Create the window using the the specified window superclass
}

char *m_pSuperClassWindow;
};

Amn
September 27th, 2002, 12:40 PM
Yes i have read some reviews of WTL, and seen some samples, i also read an introduction to WTL by its author. But i never seen whats its guts, how it is built. Author never showed the details of the implementation, so i can only assume its overhead. I know MFC overhead is ridiculous for example, but some people find it paying off when writing medum sized applications. It is a matter of taste. So to conclude, i will continue R&D but will grab any WTL text book ASAP to educate myself, so i am not reinventing the wheel. MFC is history for me though.

Regarding "pWindow = new window("EDIT")"... no it is a very clean and straightforward nicely designed approach. I haven't really found out whether it suits me as a matter of fact ;) i mean, i am ACTUALLLY SITTING WITH R&D RIGHT NOW... It s hard to think that stuff alone without counter opinions, but conversing to you gives me food to the brain...

However if we think generic OO nice patterns come out:

class WNDCLASSEX //actually struct
{

}

defines a window class. In c++ terms we have got a C++ class defining a window class. In c++ terms we can assume this is a template then, because a template also defines a class.
So what i am trying to do is create a framework that will treat window classes as c++ classes based on templates:

Somethink similiar to:

class window::edit: public window::registered<"EDIT">
{
//add some wrappers for functions edit control can perform
//since most of them are called with messages, something
//that will create a mess in the code
}

Tired of typing, hope you catch my point, i am a terrible writer, or i have had too little time to express my idea. Indeed, this is interesting topic.

TruBic
September 27th, 2002, 12:59 PM
Hello there Ann & Yves

Your topic's quite interesting. I'm having the same idea as Ann. I don't know why ATL/WTL does a weird thing to create a window. It use a macro that expand to a static function to retrieve information of a window class. And then use this function in the a window creatation. That's limit us a lot and not clear as well.

I'm thinking of write a window class that can create a window object. Similar to a ClassFactory create COM object.

Amn
September 27th, 2002, 01:12 PM
Hi TruBic, welcome to the discussion ;)

Well, its not like i DO object the WTL/ATL but ...Could you explain your idea better ?

TruBic
September 27th, 2002, 01:38 PM
I doesn't object ATL/WTL either. I just wonder why they do the weird thing.

What i mean is in order to create a window. We need to have an ATOM return when we register a window class. ATL did do that in their CWndClassInfo.

But instead let the CWndClassInfo create a window they let CWindowImpl create the window. But in order to create the window CWindowImpl need the ATOM from CWndClassInfo. So they define some special macros to get reference to CWndClassInfo. This is one of the macro:


#define DECLARE_WND_CLASS(WndClassName) \
static CWndClassInfo& GetWndClassInfo() \
{ \
static CWndClassInfo wc = \
{ \
{ sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, \
0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
}; \
return wc; \
}


The inconvinience is when want to customize some details of the class info then we have to declare new macros, re-write CWindowImpl and insert our new macro in. Everything is the same, the only difference is we replace the DECLARE_WND_CLASS macro by our macro!

That's why I think let the CWndClassInfo create the window and return a pointer to the window object. By that way we can change whatever details of the CWndClassInfo as we like and don't have to re-write anything.

Yves M
September 27th, 2002, 01:48 PM
TruBic, there is an easier way of doing this ATL. You just add a member function to your control that overrides GetWndClassInfo.


static CWndClassInfo& GetWndClassInfo()
{
static CWndClassInfo wc =
{
{ sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc,
0, 0, NULL, NULL, NULL, NULL, NULL, "TestWindowType", NULL },
// (HBRUSH) COLOR_WINDOW + 1
NULL, NULL, NULL, TRUE, 0, _T("")
};
return wc;
}


For WTL, you can actually look at its source code. It's not nearly as complicated as MFC or the ATL innards.

TruBic
September 27th, 2002, 02:00 PM
Thanks for the help Yves. I got ATL point now.

TruBic
September 27th, 2002, 02:27 PM
Hang on Yves, I think I have to override the Create function as well, do I ?

Let say I create new type of window based on CWindowImpl then I have to do the following:

CMyWindow : public CWindowImpl<CMyWindow>
{
static CWndClassInfo& GetWndClassInfo()
{
static CWndClassInfo wc =
{
{ sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc,
0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, "MyWindowClassName", NULL },
NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
};
return wc;
}

HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
{
return CWindowImpl<CMyWindow>::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
}
};


Is it right ?

Yves M
September 27th, 2002, 02:45 PM
Well, no ;) Since you derive from CWindowImpl, you'll see that CWindowImpl will actually use the information you provide in GetWndClassInfo.

HWND CWindowImpl::Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
if (T::GetWndClassInfo().m_lpszOrigName == NULL)
T::GetWndClassInfo().m_lpszOrigName = GetWndClassName();
ATOM atom = T::GetWndClassInfo().Register (&m_pfnSuperWindowProc);

dwStyle = T::GetWndStyle(dwStyle);
dwExStyle = T::GetWndExStyle(dwExStyle);

return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName,
dwStyle, dwExStyle, nID, atom, lpCreateParam);
}

TruBic
September 27th, 2002, 03:20 PM
Oh yeah, that T's so important and I ignore it. Thanks Yves.

Yves M
September 27th, 2002, 03:45 PM
There is no magic about the "T", its simply the template parameter for CWindowImpl<class T>. So since you specify your own class as the parameter, calling some function like T::func() means that you call a static function on your own class.

CWindowImpl provides a default implementation for GetWndClassInfo by using the DECLARE_WND_CLASS macro you were referring to, but since this is C++, your implementation will override the default one ;)

jfaust
September 27th, 2002, 09:50 PM
Originally posted by Yves
Although I'm still not quite sure that it's really useful to put constants into template parameters.


It's quite when using static array sizes, which must be const. Imagine:


template<int N, type T>
class fixed_size_array
{
/* ... */
private:
T m_data[N]
};


This is faster than using dynamic memory. Boost has a great array class based on this. This array class
also has some other interesting features, such that it can take an initializer list of values.

I've used it personally for an n-tree implementation--basically a tree with each node having n children.

Jeff