Sie sind auf Seite 1von 5

Tech Talk about C++ Templates / Comeau C++ Template FAQ

http://www.comeaucomputing.com/techtalk/templates/

Tech Talk About C++ Templates Comeau C++ Template FAQ


Copyright 2000-2008 Comeau Computing. All rights reserved. Note that this is a live web page, in the sense that we'll be adding new discussions as appropriate, so stop by from time to time. This web page is evolving (Version 1.6, August 6, 2008), so if you see something not right, or have a question that is appropriate (note this FAQ is not a templates tutorial) please email us about it. The intent of this page is to address questions about C++ templates. It is a spin off of http://www.comeaucomputing.com/techtalk, which discusses some general C++ and C issues. You may also want to check out http://www.comeaucomputing.com/techtalk/c99, which discusses some aspects of C99, the latest revision of Standard C. This page addresses templates issues that come up often, perhaps too often. However, it is exactly the frequency of these topics that is the reason for including a discussion of them below. These issues usually come up as having originated from a misleading statement commonly made, or from code shown in a book. These points have found themselves here as the result of our connection to the C++ and C communities for 20 years, whether teaching, helping in newsgroups, providing tech support for Comeau C++, or just plain listening to folks' issues. Some of the topics below may be found in other FAQs. In the Comeau FAQs we do not just regurgitate the same info but try to offer more information on the respective topics, as well as issues related to them. As mentioned, we expect further expansion of some of the topics below, in addition to adding new topics. Here's the current topics: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. What book do you recommend? Where is the FAQ for the various C and C++ newsgroups? What is the difference between a template class and a class template? What is the difference between a template function and a function template? What's the export keyword about? Why do I get a link error when compiling my templates? What's wrong with saying vector<int>*? Is vector<int>* the same as vector<int *>? How to define a member function outside of its template? How to define a nested template outside of its enclosing template? Why won't object.function<SomeT>(); compile? Why won't template <typename T> T foo(); compile? What is the ->template, .template and ::template syntax about? How can I pass a "string literal" to a template? What's a template template parameter? Why aren't functions used in my template being found? Why aren't types used in my template being found? Why is this->member needed? What is the template typename keyword used for? What's the difference between typename and typedef? What's wrong with saying xyz<abc<int>>? What's wrong with saying friend class T within a template? Do you have a question to add??

What book do you recommend?


We don't recommend a book. It's naive to expect that one book could be so encompassing as to satisfy everybody and every topic. Therefore, we suggest that you get a few. What you should do is to check out our literature suggestions at http://www.comeaucomputing.com/booklist as most of these books have withstood the test of time. Take the list with you to your favorite online or local technical bookstore. Take your time -- maybe an hour or more -- and browse the books for what looks right for you. Note that we've broken our list down into categories, consider getting one or two from each category. Some you should get as references, others you should get to read from cover to cover. Note that often there is a problem between technical accuracy and readability. You may have a very readable book that's telling you wrong things, or avoiding fundamentals or insights, but that's won't get you anywhere to be reading the wrong things albeit easily. The converse is a very accurate book that is not as easy to read. There is a price to pay either way, but generally you're better off with the technically correct text. We believe this is so for the short and long term. And in general, please make an effort to avoid product oriented books, or books with titles that just make things sound like everything will just be so great. Categorically, we have not been satisfied with online tutorials (this does not mean that there are no good ones, just that we have not seen it yet). If you know of one that's excellent, don't hesitate to email us about it.
Back to Top Back to Comeau Home

Where is the FAQ for the various C and C++ newsgroups?


Newsgroup
news:alt.comp.lang.learn.c-c++ news:comp.lang.c news:comp.std.c news:comp.lang.c++ news:comp.lang.c++.moderated news:comp.std.c++

FAQ URL
http://www.comeaucomputing.com/learn/faq http://www.eskimo.com/~scs/C-faq/top.html http://c-faq.com http://www.parashift.com/c++-faq-lite/ Welcome to comp.lang.c++ http://www.slack.net/~shiva/welcome.txt http://www.jamesd.demon.co.uk/csc/faq.html

http://www.comeaucomputing.com/techtalk The Comeau C++ and C FAQ This document (The Comeau C++ TEMPLATES FAQ) http://www.comeaucomputing.com/techtalk/templates http://www.comeaucomputing.com/techtalk/c99 The Comeau C99 FAQ

In general, if you need a FAQ, check out http://www.faqs.org


Back to Top Back to Comeau Home

What is the difference between a template class and a class template? What is the difference between a template function and a function template?
The question is: What is being modified? Generally speaking, if we say something is a "green house" the object is a house, that happens to be green. With that in mind, this is clearly a class:
struct SomeClass { int i; };

whereas this is clearly a template:


template <typename T> struct cTemplate { int member; };

What kind of template is it? cTemplate a class template. Along these same lines, this is a function:
void foo() {}

and this is a template:


template <typename T> T fTemplate(T arg) { return arg * arg; }

What kind of template is it? fTemplate is a function template. Now, SomeClass is a class name, and hence allows us to write something such as:
SomeClass sc;

Along these same lines, we know we can do something such as:


cTemplate<int> cti;

In other words, cTemplate<int> is a class name too. So, cTemplate<int> is a class. Think about it, it'll effectively be this when it is instantiated:
template <> struct cTemplate<int> { int member; }

What kind of class it is? Well, it's probably not necessary to qualify what kind, but if it is, it would seem to follow that cTemplate<int> is a template class. Similarly, with functions. That is, if one were to call fTemplate, for instance:
fTemplate(99.99);

then it following that a function is instantiated:


fTemplate<double>(double)

In particular, this:
template <> double fTemplate<double>(double) { return arg * arg; }

So, as above, if pressed for what kind of function this is, it seems fair to say that it is a template function. The above all said, it turns out that some folks use template class to mean the same thing as class template, so because of that, some (other) people prefer not to place a specific meaning on the former term.
Back to Top Back to Comeau Home

What's the export keyword about? Why do I get a link error when compiling my templates?
Although Standard C++ has no such requirement, some compilers require that all function templates need to be made available in every translation unit that it is used in. In effect, for those compilers, the bodies of template functions must be made available in a header file. To repeat: that means those compilers won't allow them to be defined in non-header files such as .cpp files. To clarify, in C++ese this means that this:
// ORIGINAL version of xyz.h template <typename T> struct xyz { xyz(); ~xyz(); };

would NOT be satisfied with these definitions of the ctor and dtors:
// ORIGINAL version of xyz.cpp #include "xyz.h" template <typename T> xyz<T>::xyz() {} template <typename T> xyz<T>::~xyz() {}

because using it:


// main.cpp #include "xyz.h" int main() { xyz<int> xyzint; return 0; }

will produce an error. For instance, with Comeau C++ you'd get:
C:\export>como xyz.cpp main.cpp C++'ing xyz.cpp... Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86 Copyright 1988-2004 Comeau Computing. All rights reserved. MODE:non-strict warnings microsoft C++ C++'ing main.cpp... Comeau C/C++ 4.3.4.1 (May 29 2004 23:08:11) for MS_WINDOWS_x86 Copyright 1988-2004 Comeau Computing. All rights reserved. MODE:non-strict warnings microsoft C++ main.obj : error LNK2001: unresolved external symbol xyz<T1>::~xyz<int>() [with T1=int] main.obj : error LNK2019: unresolved external symbol xyz<T1>::xyz<int>() [with T1=int] referenced in function _main aout.exe : fatal error LNK1120: 2 unresolved externals

because there is no use of the ctor or dtor within xyz.cpp, therefore, there is no instantiations that needs to occur from there. For better or worse, this is how templates work. One way around this is to explicitly request the instantiation of xyz, in this example of xyz<int>. In a brute force effort, this could be added to xyz.cpp by adding this line at the end of it:
template xyz<int>;

which requests that (all of) xyz<int> be instantiated. That's kind of in the wrong place though, since it means that everytime a new xyz type is brought about that the implementation file xyz.cpp must be modified. A less intrusive way to avoid that file is to create another:
// xyztir.cpp

1 of 5

1/22/2011 2:00 AM

Tech Talk about C++ Templates / Comeau C++ Template FAQ

http://www.comeaucomputing.com/techtalk/templates/

#include "xyz.cpp" // .cpp file!!!, not .h file!! template xyz<int>;

This is still somewhat painful because it still requires a manual intervention everytime a new xyz is brought forth. In a non-trivial program this could be an unreasonable maintenance demand. So instead, another way to approach this is to #include "xyz.cpp" into the end of xyz.h:
// xyz.h // ... previous content of xyz.h ... #include "xyz.cpp"

You could of course literally bring (cut and paste it) the contents of xyz.cpp to the end of xyz.h, hence getting rid of xyz.cpp; it's a question of file organization and in the end the results of preprocessing will be the same, in that the ctor and dtor bodies will be in the header, and hence brought into any compilation request, since that would be using the respective header. Either way, this has the side-effect that now every template is in your header file. It could slow compilation, and it could result in code bloat. One way to approach the latter is to declare the functions in question, in this case the ctor and dtor, as inline, so this would require you to modify xyz.cpp in the running example. As an aside, some compilers also require that some functions be defined inline inside a class, and not outside of one, so the setup above would need to be tweaked further in the case of those compilers. Note that this is a compiler issue, not one of Standard C++, so not all compilers require this. For instance, Comeau C++ does not, nor should it. Check out http://www.comeaucomputing.com/4.0/docs/userman/ati.html for details on our current setup. In short, Comeau C++ supports many models, including one which comes close to what the export keyword's intentions are (as an extension) as well as even supporting export itself. Lastly, note that the C++ export keyword is intended to alleviate the original question. However, currently Comeau C++ is the only compiler which is being publicized to support export. See http://www.comeaucomputing.com/4.0/docs/userman /export.html and http://www.comeaucomputing.com/4.3.0/minor/win95+/43stuff.txt for some details. Hopefully as other compilers reach compliance with Standard C++, this situation will change. In the example above, using export means returning to the original code which produced the linker errors, and making a change: declare the template in xyz.h with the export keyword:
// xyz.h export // ... ORIGINAL contents of xyz.h ...

The ctor and dtor in xyz.cpp will be exported simply by virtue of #includeing xyz.h, which it already does. So, in this case you don't need xyztir.cpp, nor the instantiation request at the end of xyz.cpp, and you don't need the ctor or dtor manually brought into xyz.h. With the command line shown earlier, it's possible that the compiler will do it all for you automatically. For instance, in the case of Comeau C++ it does.
Back to Top CHECK OUT DETAILS OF Comeau C++ WITH EXPORT

What's wrong with saying vector<int>*? Is vector<int>* the same as vector<int *>?
Many beginners do something like this:
#include <vector> int main() { vector<int>* x; // AA // ... return 0; }

The first problem with this code is that the C++ standard library is in namespace std. For details on why this is significant, check out http://www.comeaucomputing.com/techtalk/#whystd. One way of resolving this gives:
#include <vector> int main() { std::vector<int>* x; // BB // ... return 0; }

The second problem is that although there is nothing inherently wrong with this, often what is wanted is this:
std::vector<int *> x; // CC

Take note that in BB that x is a pointer to a vector<int> whereas in CC it is a vector<int *> (a vector that holds pointers to ints), two different things. Which you want/need is of course up to you, but do be clear on the difference. Of course, you may want this:
std::vector<int *>* x; // DD

a pointer to a vector of pointers to int.


Back to Top Back to Comeau Home

How to define a member function outside of its template?


It is not ok to provide the definition of a member function of a template class like this:
// This might be in a header file: template <typename T> class xyz { void foo(); }; // ... // This might be later on in the header file: void xyz<T>::foo() { // generic definition of foo() }

This is wrong for a few reasons. So is this:


void xyz<class T>::foo() { // generic definition of foo() }

The proper definition needs the template keyword and the same template arguments that the class template's definition was declared with. So that gives:
template <typename T> void xyz<T>::foo() { // generic definition of foo() }

Note that there are other types of template directives, such as member templates, etc., and each takes on their own form. What's important is to know which you have so you know how to write each flavor. This is so especially since the error messages of some compilers may not be clear as to what is wrong. And of course, get a good and up to date book. If you have a nested member template within a template:
template <typename T> struct xyz { // ... template <typename U> struct abc; // ... };

How do you define abc outside of xyz? This does not work:
template <typename U> struct xyz::abc<U> { // Nope // ... };

nor does this:


template <typename T, typename U> struct xyz<T>::abc<U> { // Nope // ... };

You would have to do this:


template <typename T> template <typename U> struct xyz<T>::abc { // ... };

Note that it's ...abc not ...abc<U> because abc is a "primary" template. IOWs, this is not good:
// <U> not allowed here: template <typename T> template <typename U> struct xyz<T>::abc<U> { }; Back to Top Back to Comeau Home

Why won't object.function<SomeT>(); compile? Why won't template <typename T> T foo(); compile? What is the ->template, .template and ::template syntax about?
Some older/broken compilers require that all the template arguments to a function template be used in the function's parameter list:
template <typename T, typename U> T foo(T arg1, U arg2); // ok, both T and U used template <typename T, typename U> T bar(U arg1); // some compilers reject because // T only appears in the return type

The Standard however allows this (although very early drafts did not). As an artifact of such behavior for those compilers, note that they also do not allow for T to be explicitly specified:
template <typename T, typename U> T bar(U arg1); // supposed to be ok // ... bar<int>(99.99); // T is explicitly specified as int // U is deduced to be double

Again, although some older/broken compilers reject this, the Standard allows this. In order to get around compilers that do not accept this, clearly you need to code it some other way. One way is to add a "dummy" function argument:
template <typename T, typename U> T bar(const T &dummyArg, U arg1); // ... int dummyInt; int someInt = bar(dummyInt, 99.99); // pick up T from 1st arg

Back to other aspects, make note that explicit specification is also allowed when member templates are used. That might lead one to the following code:
struct xyz { template <typename T, typename U> T memTemplate(T arg1, U arg2); // supposed to be ok template <typename T, typename U> T mt(U arg1); // supposed to be ok }; int foo(xyz &object) { int someInt; someInt = object.memTemplate(99, 99.99); someInt = object.memTemplate<int>(99, 99.99); someInt = object.mt<int>(99.99); // AA: ok return someInt; }

Any modern compiler should accept and correctly compile this. If we modify the example somewhat:
struct xyz { template <typename T, typename U> T memTemplate(T arg1, U arg2); // supposed to be ok template <typename T, typename U> T mt(U arg1); // supposed to be ok }; template <class T> T foo(T blah) { xyz object; T someInt; someInt = object.memTemplate(99, 99.99); someInt = object.memTemplate<int>(99, 99.99); someInt = object.mt<int>(99.99); // BB: ok return someInt;

2 of 5

1/22/2011 2:00 AM

Tech Talk about C++ Templates / Comeau C++ Template FAQ

http://www.comeaucomputing.com/techtalk/templates/

to make foo a template, and shift some declarations, it should still compile. However, if we change the code again, this time it changes the playing field somewhat:
template <class X> struct xyz { template <typename T, typename U> T memTemplate(T arg1, U arg2); // supposed to be ok template <typename T, typename U> T mt(U arg1); // supposed to be ok }; template <class T> T foo(xyz<T> &object) { T someInt; someInt = object.memTemplate(99, 99.99); someInt = object.memTemplate<int>(99, 99.99); // CC: ill-formed someInt = object.template memTemplate<int>(99, 99.99); // DD: well-formed someInt = object.mt<int>(99.99); // EE: ill-formed someInt = object.template mt<int>(99.99); // FF: well-formed return someInt; }

as xyz is now a template too. The problem is not that xyz is a template per se, but that object's type is now dependent upon T. So as usual, mt can be called with an explicitly specified template (not function) parameter (the "<int>"). But notice the difference between lines CC and DD, as well as EE and FF, above. Because object's type depends upon T, that means that the call to mt must be prefixed by the template keyword if it's to use the <int>. The Standard requires it in this context, but if it's not, some compilers may still accept it (by figuring it out). However, some interpret it as a less-than operator, and since it was not the intent to do a comparison, no less against a type, you are expected to get an error:
Comeau C/C++ 4.3.8 (Sep 25 2006 11:02:23) for _MS_WINDOWS_x86 Copyright 1988-2006 Comeau Computing. All rights reserved. MODE:strict errors C++ "tpre3.cpp", line 16: error: type name is not allowed someInt = object.memTemplate<int>(99, 99.99); // CC: ill-formed ^ "tpre3.cpp", line 16: warning: expression has no effect someInt = object.memTemplate<int>(99, 99.99); // CC: ill-formed ^ "tpre3.cpp", line 19: error: type name is not allowed someInt = object.mt<int>(99.99); // EE: ill-formed ^

As you can see from the diagnostic, the same situation exists for memTemplate on line CC needing to be brought into the form of line DD. Watch out for this! As you can imagine, the diagnostics from some compilers on something such as this could be quite confusing. Note that this is the situation for pointer cases too:
...xyz<T> *p;... ... p->template mt(99.99); // use ->template as p depends upon T

This need for disambiguation with a keyword in such templates is similar to the disambiguation capability of typename. Note that the C++ committee is looking into whether these uses of template, and also of typename, can be relaxed in any ways. Don't hesitate to check your code with the online version of Comeau C++, which can be found at http://www.comeaucomputing.com/tryitout . This is a good idea even if you don't run into problem with your code or compiler. Also, if you don't know what template deduction, explicit specification or member templates are, perhaps you should check out a good and recent C++ text. We have a book list available at http://www.comeaucomputing.com/booklist . Also, we at Comeau are working on some extensive template material that we'd like to make available in various forms (book, video, internet) at some point, so please sign our guestbook and note this in the comments if this interests you.
Back to Top

Look here for Comeau C++ info

How can I pass a "string literal" to a template?


Although string literals are constant'y in nature, you cannot pass a string literal to a template as a template non-type parameter. That is to say, this is not allowed:
template <const char *str> struct xyz { // ... }; // ok up to here xyz<"Comeau C++"> x; // Nope

The type of the above string is a static const char [11]. The problem is that it is not named with an identifier, hence withdrawing it as a candidate for instantiation. Take note that the above example is different than this:
template <typename T> void foo(T) { /* ... */ } // ... foo("Comeau C++ is great"); // Just fine

As this brings forth a foo<const char *>(const char *). This is not a problem because the string literal is being passed to the function and not as the template parameter itself. IOWs, this example does not use a template non-type parameter, but a template type parameter. We'd have to end up doing something such as:
foo<"Comeau">("Comeau"); // This is not valid

which as you can see wouldn't necessarily be productive to anything. Consider that the function argument would be a const char *, whereas the template argument explicitly specified is a const char [7]. No can do. So, what do you do then? How can we use xyz above to obtain the desired effect? It would require something such as:
template <const char *str> struct xyz { // ... const char *p; xyz() : p(str) { } void print() { someOutputStream << str << std::endl; } void print2() { someOutputStream << p << std::endl; } }; char Comeau[] = "Comeau C++"; xyz<Comeau> x; // Now ok // ... x.print(); x.print2();

Now, as Comeau is a named object with external linkage, such an instantiation, and use, is possible. In effect, Comeaus address will be passed to the template. Note that if Comeau had been:
static char Comeau[] = "Comeau C++";

Then you would not have been able to declare x either. It's not enough that it has a name, but a template argument must reference an external entity, and if it's static (not just static storage duration, but declared with the static keyword) then it has internal linkage.
Back to Top Have you checked out Comeau C++'s template support lately?

Why aren't functions used in my template being found? Why aren't types used in my template being found? Why is this->member needed?
Normally (for non-class templates) we can do this:
struct blah { // AA int member; void foo() { member = 99; // ok, taken implicitly as this->member this->member = 99; // ok too } };

Similarly, you may have:


struct derive : public blah { // BB void bar() { member = 99; // ok, inherited so taken as this->blah::member this->member = 99; // ok too blah::member = 99; // ok too this->blah::member = 99; // ok too };

You could even have the following:


template <typename T> // CC struct someBase { int member; }; struct derive2 : public someBase<double> { void baz() { member = 99; // ok, someBase<double> is concrete "as usual" } };

This is fine because everything is spelled out, and so in CC, no name depends upon a template parameter. However, let's say we have the following instead of derive2:
template <typename T> // DD struct someTemplate : public someBase<T> { void foo() { member = 99; } };

When compiled with Comeau C++ this produces:


G:\tmp>como --A depn.cpp Comeau C/C++ 4.3.4.1 (Sep 19 2004 11:33:48) for MS_WINDOWS_x86 Copyright 1988-2004 Comeau Computing. All rights reserved. MODE:strict errors C++ "depn.cpp", line 9: error: identifier "member" is undefined member = 99; ^ 1 error detected in the compilation of "depn.cpp".

Note that the error is produced even though we have not yet uttered a specific instantiation for someTemplate or someBase. The reason for this error is similar to why typename is often necessary in some of your code, as well as why the .template syntax when qualifying a member name in an expression is often necessary (note the dot). In short, templates as described by Standard C++ need more initial processing than the original pre-standard template proposal. That is to say, in this case something called dependent name lookup may need to occur while processing modern templates. An "algorithmic" implication of this is that compilers often have to be able to parse template definitions without knowing what the template arguments will be, and to do that you need prods such as typename and the other things the standard added to allow such parsing of templates. This way, for instance, a "practical" implication is that some diagnostics resulting from template use do not need to be delayed because a "factual" implication is that when possible, names used in templates are looked up "as soon as possible" (which is not always immediately). These other things for the purposes here are described below. So in the example above, there is an error because of the interactions taking place in the C++ lookup rules. It comes down to that something is dependent upon some "<T>". Not that T depends upon say a typedef, but it depends upon a template parameter. In particular, in DD, the use of someBase<T> depends upon the template parameter T, therefore the use of this base's members need to follow the rules of dependent name lookup, and hence are not directly allowed in the code above as written. To compile your code, you need to do things like: Qualify the name (in this case member) with this-> giving:
this->member = 99; // EE

Normally this is the preferred course of action. Qualify the name with theBaseName<T>:: in this case:
someBase<T>::member = 99; // FF

Because this form is now providing a qualified form of the name be careful because this form can hijack polymorphic behavior of your virtual function call schemes if you apply this form to your virtual function calls, which often is not what you want to happen. Of course, our example is using a so-called data member and not a virtual function. This form can be handy in situations where you want to use a class, typedef, etc, from a dependent base class, but using this->thatMember is not appropriate because those members will have no this pointer to them. So both forms can be helpful in different contexts.

3 of 5

1/22/2011 2:00 AM

Tech Talk about C++ Templates / Comeau C++ Template FAQ

http://www.comeaucomputing.com/techtalk/templates/

Use a using directive in the class template


template <typename T> struct someTemplate2 : public someBase<T> { // GG using someBase<T>::member; void foo() { member = 99; } };

This form is used when stating the members of the dependent bases upfront tends to be more cosmetically appealing, as they will apply to all member functions, and uses. This is instead of the constant use of the other two forms, neither normally not used unless necessary. When the using directive is used, it can seem tedious upon a class, but when grouped together, can often make things clear. As a transition strategy only, use your compiler in non-strict mode, if it supports such capability. For instance, you should also be able to get the original code to compile with Comeau C++ by using non-strict mode (the --no_A command line option) or by getting very specific and specifying the --no_dep_name option even in strict mode. Obviously if you're striving for compliant code you should avoid these kinds of options. You could also satify the problem code in DD by providing a different declaration of member. That is to say:
int member; // HH template <typename T> struct someBase2 { int member; }; template <typename T> struct someTemplate3 : public someBase2<T> { void foo() { member = 99; // error? somebase2::member, or ::member? } };

Here unlike the original code, there will be no error, because the ::member declaration in HH is able to satisfy finding the name. However, this is often not what you wanted. So be careful. In other words, we are not suggesting this as a strategy per se but as a caution. It's worth pointing out that these things do not pacify the complete lookup, nor should they. Afterall, these involve templates not yet instantiated. In short, the EE, FF, and GG suggestions are sort of placeholder requests to the compiler to delay the lookup, but to do it in an educated manner. This is just like using typename, which doesn't mean the actual entity being typename'd is actually a type, just that you expect it to be. Of course, if that is not the case, an error will be generated. For instance, if in CC we introduce:
template <> struct someBase<double> { // ..., but no declaration for 'member' provided };

Then requesting say this->member from a someBase<double> is not valid, since it has no such member. If it's not obvious by this point, the original basis for the diagnostic produced by Comeau C++ in say DD is not that member is a dependent name, but exactly the opposite: it's nondependent. And so the Standard requires it to be looked up (but not in a dependent base class!!) even though the template has not yet been instantiated. Using say this->member caused it to be dependent. Why? Since the type of this is a dependent name, it follows that the actual lookup for this->member be postposted. And just to be clear, note that this is ok:
template <typename T> // II struct someTemplate4 : public someBase2<int> { // .. other stuff void foo() { member = 99; // Ok, somebase2<int> is concrete class } };

because someBase2<int> does not depend upon template parameter T, just like example CC does not. Of course, someBase2<int> needs to have a member named member available (or there needs to be some identifier member available) or there is still an error. The above is not intended to be a complete discussion on all the nuances of C++ lookup, nor even an overview, so don't consider it complete, or covering every pathlogical example. Note that many compilers still do not support the various lookup rules fully, hence complicating things, confusing discussions in a newsgroup, etc.
Back to Top **** Check out Comeau C++'s support of dependent lookup ***

What's a template template parameter? Is a template template parameter==template parameter?


A template template parameter (will refer to this a TTP below) is not a typo for template parameter. A TTP is a template parameter that is a template itself. Template parameters can take a few different forms. For instance, this uses a template type parameter:
template <typename T> class Comeau { // ... T goodstuff; }; // ... Comeau<int> C;

There are also template non-type parameters, passed as constants, for instance:
template <int NumberOfPlatforms> class Where { // ... int counts[NumberOfPlatforms]; }; // ... Where<50> total;

And so on. As well, you are also allowed to pass a template to a template. Consider the following template template parameter:
template <template <typename T> class Product> class sales { // ... Product<int> P; }; // ... sales<Comeau> S;

TTPs provide for yet another level of abstraction capability in C++. Compilers are only recently supporting them (mid-2000), so make sure that your particular compiler does before trying to use them (if not, error messages will be confusing). On this point: Don't just assume that because your compiler is popular and/or because the vendor lies and claims conformance that their compiler really supports everything.
Back to Top Back to Comeau Home

What is the template typename keyword used for? What's the difference between typename and typedef
For starters, typename can be used instead of class when declaring template parameters, for instance this:
template <class T> class xyz { };

could have been written as:


template <typename T> class xyz { };

These two definitions of xyz are considered equivalent since template parameters using class or typename are, in that syntactic position, and in that syntactic way, interchangeable. Note the parameter is T. Which way you favor is a style issue and up to you. However, note that this is wrong:
typename xyz2 { };

as it is not describing/pertaining to a template parameter. Also, note that these are wrong:
template <class T> typename xyz3 { }; template <typename T> typename xyz4 { };

for the same reason: that use of typename outside of the angle brackets is not being applied to the template parameter and hence not allowed. Instead a class structure was desired, therefore, the intent was to define a class, as usual, not a parameterized typename for xyz3 and xyz4. Therefore, it is also wrong to change this:
template < template < typename T> class abc> class xyz5 { };

to this:
template < template < typename T> typename abc> class xyz6 { };

even though abc is a template parameter; the point of this construct is to declare a template template parameter, that is, a template parameter that is a template itself, and some of the valid forms of templates involving typename were just discussed, and the last form was not one of them. Additionally, there are various other different contexts from the above where the compiler needs to know whether it is dealing with a declaration or an expression. In the case of templates, similar parsing issues comes up. In particular, if T is a template parameter as it is in xyz above, then what does it mean for it to use say T::x? In other words, if the compiler does not know what T is until you instantiate it, how could it know what x is, since it is based upon T? Consider:
template <typename T> class xyz { void foo() { T::x * p; /* ... */ p = blah; } };

Does this declare p as a pointer to, or does it multiply some p somewhere by, T::x? If it should be a declaration, then you would do this to make that clear:
template <typename T> class xyz { void foo() { typename T::x * p; /* ... */ p = blah; } };

Now we know that blah is being assigned to the local p in foo. Note that there is no guarantee that when you actually instantiate the template that x is actually a type. If it's not, you'll get an error at that point. Anyway, make sure that typenamed things will actually eventually refer to types. Note too that some earlier compilers do not support the typename keyword at all. As well, some current compiler which do support it may have a switch to disable it, so double check your situation if your compiler won't accept your using this keyword. Furthermore, some compilers and/or modes will make an attempt to guess which names are actually supposed typenames. It can clearly do this in some cases, and in some cases it is not required because the compiler requires a type, but to expect it to do it in all cases is not possible. Also worth pointing out is that typename is not the same as typedef. In brief, typedef creates an alias (another name) for an existing type, whereas typename acts as a contextual disambiguator as described above. In fact, you will often see them used together, for instance:
template <typename T> class xyz { typedef typename T::SomeTypeInT SomeNewTypeForxyz; };

By the way, if you are using just a T, then it does not require typename, so this is wrong:
template <typename T> class abc { typedef typename T abcT; // Nope };

For instance, here is the error message from Comeau C++ about this:
Comeau C/C++ 4.2.43 (Mar 3 2000 18:18:13) for Solaris_SPARC_2_x Copyright 1988-2000 Comeau Computing. All rights reserved. MODE:strict errors C++ "tn.c", line 2: error: a class or namespace qualified name is required typedef typename T abcT; ^

There are other examples where typename can be used and their premise is similar to the above. In the start of this item, we pointed out that class and typename can be used interchangeably for template parameters. Now that you know some of the above, you should note that in the original templates proposal, typename was not available for template parameters. When the committee added typename to handle the above situations, it also decided to use it for parameters too, as some felt that using class to mean "some type" was too confusing and an awkward use (some feel it tends to mean "only classes"). As mentioned above, some earlier compilers don't support the use of typename. In mild cases, you can do some preprocessor hackery with #define typename class but that's not going to buy you much if you need it in the other cases mentioned above (since uttering class in those cases will be an error). Before leaving this subject, it's worth pointing out that there are cases where template parameters use typename that cannot be interchanged with class. For instance:
template <class T, T::member> struct xyz // ...

is an (erroneous) attempt to establish passing a type and a member of that same type (usually another type). But to refer to T::member the compiler does not know that, for the same reasons explained above. Therefore, it wants to see it prefixed by the typename keyword:
template <class T, typename T::member> struct xyz // ...

Of course, one can change the form of the declaration of T itself:


template <typename T, typename T::member> struct xyz // ...

But typename'ing T is insufficient to satisfy T::member:


template <typename T, T::member> struct xyz // ...

which is an error since as above T::member is not taken by default as a typename.


Back to Top Back to Comeau Home

What's wrong with saying xyz<abc<int>>?


4 of 5

1/22/2011 2:00 AM

Tech Talk about C++ Templates / Comeau C++ Template FAQ

http://www.comeaucomputing.com/techtalk/templates/

When you write something such as:


std::vector<std::vector<int>> x;

the problem is that >> is taken as the right shift operator (it's not taken as a positional punctuation ending the class (which happens to be based upon a template)). To get around this parsing problem, simply add a space between the greater than signs:
std::vector<std::vector<int> > x;

Even without this syntax issue, some prefer centering the whole part inside the brackets:
std::vector< std::vector<int> > x; Back to Top Back to Comeau Home

What's wrong with saying friend class T within a template?


Trying to use a template parameter in a friend is ill-formed:
template <typename T> class xyz { friend class T; // ill-formed code };

According to Section 7.1.5.3 paragraph 2 of Standard C++: 3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. ... If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: this implies that, within a class template with a template type-parameter T, the declaration
friend class T;

is ill-formed. ] The next thing one would try would be:


template <typename T> class xyz { friend T; };

but this form is not allowed either because for friends, according to 11.4 paragraph 2 An elaborated-type-specifier shall be used in a friend declaration for a class. And also from footnote #101: The class-key of the elaborated-type-specifier is required. You could also probably try some hackery with typedef, but I suspect all of these attempts will also be illegal.
Back to Top Back to Comeau Home

Do you have a question to add?


Do not hesitate to email us at support@comeaucomputing.com if you have any other questions or concerns you would like to see covered.
Back to Top Back to Comeau Home

Comeau Computing. Copyright Comeau Computing. All rights reserved. Revised: Auguest 6, 2008.

5 of 5

1/22/2011 2:00 AM

Das könnte Ihnen auch gefallen