C Board  

Go Back   C Board > General Programming Boards > C++ Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 05-25-2008, 07:18 AM   #256
Cat without Hat
 
CornedBee's Avatar
 
Join Date: Apr 2003
Posts: 8,492
What's the relationship between CStringEx, CTmplStringBase and CTmplStringBaseTmpl again?
__________________
All the buzzt!
CornedBee

"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
CornedBee is offline   Reply With Quote
Old 05-25-2008, 07:21 AM   #257
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Oh yeah, sorry about that >_<
CStringEx is the typedef name for the actual class named CTmplStringBase:
Code:
 typedef CTmplStringBase< char, StrTraits<char> > CStringExA;
	typedef CTmplStringBase< wchar_t, StrTraits<wchar_t> > CStringExW;
	typedef CTmplStringBase< TCHAR, StrTraits<TCHAR> > CStringEx;
And the rest are macros:
Code:
#	define CTmplStringBaseTmpl Strings::CTmplStringBase<T, Traits>
#	define CTmplStringBaseTemplate template<typename T, typename Traits> 
To get rid of the long nasty template lists.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-25-2008, 07:28 AM   #258
Cat without Hat
 
CornedBee's Avatar
 
Join Date: Apr 2003
Posts: 8,492
You do realize that CTmplStringBaseTemplate is not significantly shorter than template<typename T, typename Traits>, but several magnitudes less readable, right?

This is indeed weird.
__________________
All the buzzt!
CornedBee

"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
CornedBee is offline   Reply With Quote
Old 05-25-2008, 08:01 AM   #259
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Quote:
Originally Posted by CornedBee View Post
You do realize that CTmplStringBaseTemplate is not significantly shorter than template<typename T, typename Traits>, but several magnitudes less readable, right?
Perhaps, but it helps me a lot since I don't have to go to 100 places and change the code whenever it changes. Plus it's just one of many, sometimes very long.

But I also tried this. "The simplest possible snippet of code that compiles".

Code:
template<typename T> class CTest { public: CTest() {} CTest(const wchar_t*) {} };
template<typename T> void operator += (CTest<T>&, const CTest<T>&) {}

void Help()
{
	CTest<wchar_t> a;
	a += L"test";
} 
Will also give error about unable to deduce the template T.
If I remove the template and explicitly specify wchar_t, it compiles.
If I explicitly specify the constructor, such as a += CTest<wchar_t>(L"test"), it works too, but not with the templates.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-25-2008, 10:44 AM   #260
Cat without Hat
 
CornedBee's Avatar
 
Join Date: Apr 2003
Posts: 8,492
Well, GCC agrees with VC++, even though it's even less informative. Simplest solution is apparently to just make += a member function. Or overload the free operator += for const wchar_t*.
__________________
All the buzzt!
CornedBee

"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
CornedBee is offline   Reply With Quote
Old 05-25-2008, 10:46 AM   #261
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Hm. Weird.
Either a member or an overload for each of the types it can accept...
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-25-2008, 11:05 AM   #262
Registered User
 
Join Date: Jan 2008
Posts: 627
Quote:
I must be doing something wrong here...
Yep, you are trying to make the compiler guess when it can't.

Quote:
To get rid of the long nasty template lists.
You'd better hope that you don't need to extend a series.

Quote:
This is indeed weird.
It isn't weird, but it is annoying.

Also, 'operator +=' should really be a method.

Anyway, the reason this can't work: any specialization or even instantiation of 'CTmplStringBase' may have a constructor that takes a 'const wchar_t *' as an argument. How would the constructor choose between these instantiations?

You have a few options (for this and the other operators):

1): Create a less ambiguous interface that forwards to the correct implementation--by explicitly instantiating the template function.

2): Create the function as a method, losing "left hand conversion".

3): Get partial "left hand" conversion by declaring the function as a friend and implementing it "inline"--not 'inline'.

4): My way, or less arrogantly: the way of the inspiring Andrei Alexandrescu. (Note: You lose implicit 'CTmplStringBase<X>' to 'CTmplStringBase<Y>' conversion, but this too can be overcome by adding in a little '1'.)

Soma

Code:
template<typename T> class CTest { public: CTest() {} CTest(const wchar_t*) {} typedef CTest<T> this_type;};
template<typename T> void operator += (CTest<T>&, const typename CTest<T>::this_type &){}

void Help()
{
	CTest<wchar_t> a;
	a += L"test";
}
phantomotap is offline   Reply With Quote
Old 05-25-2008, 11:08 AM   #263
Cat without Hat
 
CornedBee's Avatar
 
Join Date: Apr 2003
Posts: 8,492
Quote:
the way of the inspiring Andrei Alexandrescu.
I knew there was such a thing as suppressing argument detection from the second parameter, but I couldn't remember how. My attempt 'const CTest<typename identity<T>::type>&' failed.
__________________
All the buzzt!
CornedBee

"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
CornedBee is offline   Reply With Quote
Old 05-25-2008, 11:14 AM   #264
Registered User
 
Join Date: Jan 2008
Posts: 627
Quote:
(Note: You lose implicit 'CTmplStringBase<X>' to 'CTmplStringBase<Y>' conversion, but this too can be overcome by adding in a little '1'.)
Sorry. That was just poor wording. You obviously keep conversion; what you don't keep is type information.

*shrug*

Soma
phantomotap is offline   Reply With Quote
Old 05-25-2008, 11:30 AM   #265
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Quote:
Originally Posted by phantomotap View Post
Yep, you are trying to make the compiler guess when it can't.
Apparently, that's the only I can figure.
But I would assume the compiler should be able to guess, even in this instance.

Quote:
Also, 'operator +=' should really be a method.
Maybe you're right about that. I'll move it inside the class, but there are more free operators that would break, and besides, it's just a test. Yesssss...

Quote:
Anyway, the reason this can't work: any specialization or even instantiation of 'CTmplStringBase' may have a constructor that takes a 'const wchar_t *' as an argument. How would the constructor choose between these instantiations?
It would seem to me that if that is the case, then it would be ambiguous, but not when there is only one instance and no specializations.

The way I see it:
The compiler sees that it wants a class CTest of type X.
Therefore the compiler looks at the class for CTest.
It looks for a constructor to take one argument.
It finds a constructor that takes const T*. Seeing as I add a wchar_t*, the compiler can easily deduce the type of T to wchar_t and call the constructor.
The temporary object will then be of type CTest<wchar_t> and the compiler can deduce the type of T for the operator.

But apparently my analogy is incorrect.

Quote:
4): My way, or less arrogantly: the way of the inspiring Andrei Alexandrescu. (Note: You lose implicit 'CTmplStringBase<X>' to 'CTmplStringBase<Y>' conversion, but this too can be overcome by adding in a little '1'.)
More complexity and tricks to put in the book
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-26-2008, 03:57 AM   #266
Registered User
 
Join Date: Jan 2008
Posts: 627
O_o

Quote:
It would seem to me that if that is the case, then it would be ambiguous, but not when there is only one instance and no specializations.
A particular template is "compiled" when the definition is encountered and only "instantiated" later. A specialization can be crafted after the specialization is used. The source isn't ambiguous because the compiler can't even determine where to start looking for ambiguities; the compiler knows that an unlimited number of cases may yet exist that would yield a match. How would the compiler determine what types a particular template class should be instantiated with in order to examine the interface for a particular constructor?

Quote:
The compiler sees that it wants a class CTest of type X.
No, the compiler only sees that the "left hand" argument is a 'CTest<X>'.

Quote:
Therefore the compiler looks at the class for CTest.
I think this is your biggest problem. There is no class 'CTest'. There is a class named 'CTest<X>', a class named 'CTest<Y>', and an infinite number of other classes named 'CTest<?>'.

Quote:
It looks for a constructor to take one argument.
Where? The compiler can't look at 'CTest'. It can only look at 'CTest<?>' for any given '?'. How would the compiler know which 'CTest<?>' to examine?

Quote:
It finds a constructor that takes const T*. Seeing as I add a wchar_t*, the compiler can easily deduce the type of T to wchar_t and call the constructor.
A human can rationalize circular logic, but a compiler rather likes things to be composed linearly. The compiler can't find a constructor that takes a 'const T*' because it doesn't know where to look. The compiler can't deduce the type of the template parameter because it doesn't know if any instantiation supports such a constructor. (The compiler literally doesn't know the layout of a template class until it is instantiated.)

Quote:
The temporary object will then be of type CTest<wchar_t> and the compiler can deduce the type of T for the operator.
This, again, is composed of circular logic. If the compiler can't determine the type of 'T' it can't create a temporary of type 'CTest<wchar_t>' in the first place.

For the foreseeable future, keep this thought in your head when programming with templates: only the instantiations of templates actually exist.

Soma

Last edited by phantomotap; 05-26-2008 at 04:02 AM. Reason: Elysia
phantomotap is offline   Reply With Quote
Old 05-26-2008, 04:38 AM   #267
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Quote:
Originally Posted by phantomotap View Post
I think this is your biggest problem. There is no class 'CTest'. There is a class named 'CTest<X>', a class named 'CTest<Y>', and an infinite number of other classes named 'CTest<?>'.
I think that is the problem right there. The compiler is too inflexible. The class should not be named CTest<?>, but CTest, because however you look at it, there will only be one CTest and its specializations. Therefore, the compiler can scan for any template classes whose class name is CTest, even though it may not exist.
But I guess we don't have that luxury.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-26-2008, 05:24 AM   #268
Registered User
 
Join Date: Jan 2008
Posts: 627
Quote:
I think that is the problem right there. The compiler is too inflexible. The class should not be named CTest<?>, but CTest, because however you look at it, there will only be one CTest and its specializations. Therefore, the compiler can scan for any template classes whose class name is CTest, even though it may not exist.
But I guess we don't have that luxury.
O_O

You expect a compiler to examine a class that does not yet even potentially exist? (Edit: Yes CornedBee, that was derisive.)

And anyway, that still doesn't answer the crucial question: where does the compiler start its examination? If you were to call every 'CTest<?>' by the name 'CTest', how would the compiler determine if any 'CTest' had a constructor taking a 'const wchar_t *'? (Remember, you just named the template argument relevant 'CTest<wchar_t>' constructor as taking a 'const self::arguments::_1 *' which may or may not be the same as 'const wchar_t *'.) If you look at every 'CTest<?>' by the name 'CTest', and a construct taking a 'const wchar_t *' is found, how do you determine the template arguments over any other valid arguments? (That is, how would you determine the types to pass to the parameters of the template if a partial specialization exists that has a constructor taking a 'const wchar_t *' regardless of the types the template is instantiated with?)

By the by, this is also why you need 'template<typename T> void operator += (const typename CTest<T>::this_type &, CTest<T>&);'. Even with the existence of the companion operator the compiler can't know where to being, so it doesn't try.

Soma

Last edited by phantomotap; 05-26-2008 at 05:28 AM.
phantomotap is offline   Reply With Quote
Old 05-26-2008, 05:39 AM   #269
Mysterious C++ User
 
Elysia's Avatar
 
Join Date: Oct 2007
Posts: 14,771
Quote:
Originally Posted by phantomotap View Post
You expect a compiler to examine a class that does not yet even potentially exist? (Edit: Yes CornedBee, that was derisive.)
But there is the thing - why should templates by special? It you provide a class definition, then the class would indeed exist.
So even if we append template before the class, it should be considered as a valid definition. The class CTest would exist, but not CTest<?> (no CTest<int>, no CTest<float>). Basically, no fully qualified class (full class type) would exist, but the general declaration of the template class, named CTest does exist.

Quote:
And anyway, that still doesn't answer the crucial question: where does the compiler start its examination? If you were to call every 'CTest<?>' by the name 'CTest', how would the compiler determine if any 'CTest' had a constructor taking a 'const wchar_t *'?
Again, why should templates be special? It can search from the line upwards to find a definition of CTest. If it does not exist in the current file, then a header with the definition could be included.
If one or more specializations of the class does not exist in that header, then it's a programmer error, because this is just how normal classes works, as well. A full definition, including potential specializations. Then the compiler would be able to find the definition it seeks.

Quote:
(Remember, you just named the template argument relevant 'CTest<wchar_t>' constructor as taking a 'const self::arguments::_1 *' which may or may not be the same as 'const wchar_t *'.)
I'm not sure I understand this one.
Let's look at a source:
Code:
template<typename T> class CTest { CTest(const T*) {} };
As from what I understand, the compiler cannot create a CTest without explicit type (eg CTest<char>) because it doesn't know beforehand what function you are going to call. But if it could search inside the class for a function that takes one argument...
If it finds one, then it could try to match the argument I pass against T and see if it can generate an implicit conversion to const T*:
Code:
template<typename T> class CTest { CTest(const T*) {} };
int main()
{
CTest test("my test");
}
In this code, the compiler should search for a constructor that takes one argument.
Then it can translate T = char* (because it's the argument we pass), so the constructor becomes:
CTest(const char*)
Then it will see if it can implicitly convert the argument we pass to that type. If it is successful, it calls the constructor and everyone is happy.

But if it cannot match the type, then it must complain it cannot deduce T.
If it finds several functions that may match, then it must complain ambiguous.

Quote:
If you look at every 'CTest<?>' by the name 'CTest', and a construct taking a 'const wchar_t *' is found, how do you determine the template arguments over any other valid arguments? (That is, how would you determine the types to pass to the parameters of the template if a partial specialization exists that has a constructor taking a 'const wchar_t *' regardless of the types the template is instantiated with?)
If that's the case (if the compiler sees those specializations, that is), then the compiler would obviously be confused and return an ambiguous error.
__________________
Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System
I dedicated my life to helping others. This is only a small sample of what they said:
"Thanks Elysia. You're a programming master! How the hell do you know every thing?"
Quoted... at least once.
Quote:
Originally Posted by cpjust
If C++ is 2 steps forward from C, then I'd say Java is 1 step forward and 2 steps back.
Elysia is offline   Reply With Quote
Old 05-26-2008, 07:08 AM   #270
Registered User
 
Join Date: Jan 2008
Posts: 627
Quote:
But there is the thing - why should templates by special? It you provide a class definition, then the class would indeed exist.
Templates are templates. They aren't special.

Quote:
So even if we append template before the class, it should be considered as a valid definition. The class CTest would exist, but not CTest<?> (no CTest<int>, no CTest<float>). Basically, no fully qualified class (full class type) would exist, but the general declaration of the template class, named CTest does exist.
And thus, the other problem: you can't say that the constructor taking a 'const the_same_type_as_the_first_template_argument *' of 'CTest' actually takes a 'const wchar_t *' because you've not yet assigned those arguments values/types. Without a fully instantiated template you can't determine if the referenced types of the template arguments support any construct.

Quote:
Again, why should templates be special? It can search from the line upwards to find a definition of CTest. If it does not exist in the current file, then a header with the definition could be included.
I have no idea what you mean to be saying. C++ doesn't parse anything upwards.

Quote:
If one or more specializations of the class does not exist in that header, then it's a programmer error, because this is just how normal classes works, as well. A full definition, including potential specializations. Then the compiler would be able to find the definition it seeks.
Requiring that a specialization appears before its first use changes nothing about how a compiler might determine which specialization to instantiate.

Quote:
I'm not sure I understand this one.
It's simple. You can't examine the values associated with the parameters of a function before it is called; by the same logic, you can't determine the types associated with template parameters until it is instantiated.

Quote:
As from what I understand, the compiler cannot create a CTest without explicit type (eg CTest<char>) because it doesn't know beforehand what function you are going to call.
Nope. It's much simpler than that. The compiler can't create a 'CTest' without an explicit type period. It can't because it is a template by which other types are crafted.

Quote:
But if it could search inside the class for a function that takes one argument...
The compiler can and does search inside a class for conversion functions. That isn't the problem. The compiler doesn't know which class to search.

Quote:
If it finds one, then it could try to match the argument I pass against T and see if it can generate an implicit conversion to const T*:
A generic 'T' matches everything. If I have a partial specialization of 'CTest', before the point of invocation or later in the source, named 'template <typename T> CTest<type_vector<T, T>>' that "always" has a constructor taking 'const wchar_t *' as a parameter how do you determine what value 'T' should have? You can't. The compiler can't, and the compiler doesn't try.

Quote:
Then it will see if it can implicitly convert the argument we pass to that type. If it is successful, it calls the constructor and everyone is happy.
Your example is logically wrong, but I'll give you the befit of doubt. (That is, I'll assume your going to correct the inconsistencies.) I'll even give you some "source"--like yours--of my own for you to chew over. Actually, I'll give you two different chunks.

Code:
template <typename T> class CTest {CTest(const T*){} typedef T type;};
template <typename T> class CTest<type_vector<T, T>> {CTest(const char *){} typedef type_vector<T, T> type;};
int main()
{
CTest test("my test");
}
Which template class did I intend to instantiate?
Which instantiation is more appropriate? Why?
What would 'type' be a typedef for? And in the other case?

Code:
template <typename T> class CTest {CTest(){} typedef T type;}; // Note: Constructor
template <typename T> class CTest<type_vector<T, T>> {CTest(const char *){} typedef type_vector<T, T> type;};
int main()
{
CTest test("my test");
}
There is no ambiguity here; what would 'type' be a typedef for?

Quote:
But if it cannot match the type, then it must complain it cannot deduce T.
That is what the compiler said. The only difference is that the compiler never made it to the constructor call because it could not deduce the type of the class to search for a specific constructor.

Quote:
If it finds several functions that may match, then it must complain ambiguous.
It couldn't determine the type to instantiate the template class with so it couldn't begin looking for ambiguities; the compiler couldn't complain of ambiguities because it couldn't be sure of any.

Soma
phantomotap is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
WS_POPUP, continuation of old problem blurrymadness Windows Programming 1 04-20-2007 06:54 PM
Laptop Problem Boomba Tech Board 1 03-07-2006 06:24 PM
implementation file bejiz C++ Programming 5 11-28-2005 01:59 AM
Sorting problem.. well actually more of a string problem fatdunky C Programming 5 11-07-2005 11:34 PM
Memory Problem - I think... Unregistered C Programming 4 10-24-2001 12:14 PM


All times are GMT -6. The time now is 08:21 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22