Sure they are. The compiler refuses to see them as a unspecialized type. Therefore, CTest does not exist, but CTest<int> might (at the point where the code uses a CTest<int> class).
But that's just the thing! If the compiler looked inside the class for a proper constructor, it should be able to guess the type of T. If it looked at my const T* constructor, it should be able to guess the type of T = wchar_t, and replace T with wchar_t and seeing as the argument is const wchar_t* and the constructor takes const wchar_t*, the compiler made a good guess that works and thus it have deduced T.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.
This is what I was referring to that a compiler could do (but apparently doesn't).
In essence that you cannot use a class which hasn't been defined up to the point where you use it (it must be available on a previous line somewhere, thus "upwards".)I have no idea what you mean to be saying. C++ doesn't parse anything upwards.
Of course it does. Or would. In the ideal compiler.Requiring that a specialization appears before its first use changes nothing about how a compiler might determine which specialization to instantiate.
Because then the compiler would be able to see all possible outcomes of the class CTest before the instantiation line. Thus it can parse all of those to see if it can find a match to its liking. Omitting them is the same as omitting half the definition of a class. Or would be. A specialization is part of the class CTest, part of the unspecialized class.
Right, but the idea was that the compiler could guess.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.
This is what shouldn't be. The compiler should be able to guess and try to resolve the ambiguity by checking the class and see if it can match a type.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.
It shouldn't give up just because the instantiation is unspecialized.
There's only one unspecialized class, so search all parts of itThe 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.
It can still resolve T to a type and then use the rules for best overloaded function to call. If it can't decide - then it will just return error - ambiguous.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.
It's not wrongYour 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.
The compiler would unfold the code to:Which template class did I intend to instantiate?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 instantiation is more appropriate? Why?
What would 'type' be a typedef for? And in the other case?
And since there are two templates with the same constructor (one argument, T*), it will complain ambiguous.Code:template <> class CTest {CTest(const char*){} typedef char* type;}; template <> class CTest<type_vector<char*, char*>> {CTest(const char *){} typedef type_vector<char*,char*> type;}; int main() { CTest test("my test"); }
There is no ambiguity here; what would 'type' be a typedef for?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"); }Since only the second class matches the number of arguments in the list, it would instantiate the second and thus type = type_vector<char*, char*>.Code:template <> class CTest {CTest(){} typedef char* type;}; // Note: Constructor template <> class CTest<type_vector<char*, char*>> {CTest(const char *){} typedef type_vector<char*, char*> type;}; int main() { CTest test("my test"); }
At least in the ideal compiler.