C++ Templates: The Complete Guide
The C++ programming language is widely regarded as a good systems programming language, albeit a complex one fraught with low-level details and issues (though arguably this is what makes it good for certain kinds of systems programming). For perhaps a decade now, C++ has had a template mechanism - in programming language circles, it might more properly be called a form of parametric polymorphism. The template mechanism, like many other forms of parametric polymorphism, is potentially extremely powerful, but the complexity of C++ makes it tough to thoroughly master. That's where this book comes in.
Most likely, an experienced C++ programmer has at least used templates. If nothing else, use of the Standard Template Library (or STL) requires at least knowledge of how to use templates. If you use C++ enough to care about templates, you probably know what they are, at least roughly, and if you don't, this isn't the book from which to learn about them. It very clearly requires (and explicitly states in the introduction) that you need to know C++ before making effective use of the book.
Designing template classes, however, is another kettle of fish, and if you're in a position where you're building template classes for someone else to use, you probably need this book. Unless, like the book's authors, you moderate comp.lang.c++.moderated. If you are such a super C++ guru, you may still find this book useful - it is a truly stupendous catalog of the capabilities and subtleties of C++ templates. If nothing else, you'll find examples for well nigh every use to which you are likely to put C++ templates.
The book's strengths, then, are its authoritative and exhaustive detail. On the downside, its examples are dry and flavorless. Perhaps this is intentional, as a way to suggest how some feature can be used in a variety of situations. I prefer a combination of specific, concrete examples, followed by a generic example. The specifics motivate the need for a capability, while the generic showcases the broad, interrelated aspects of the capability. The authors didn't follow that approach. I would suspect this comes in part from their mutual roles in C++ standards bodies - a specific example could be seen as too limiting, and so were left out.
Another drawback, to my thinking, is its resolute focus on C++ to the exclusion of all other languages. Don't get me wrong - I read the title, and it's a C++ book, so I don't expect it to teach me Scheme, much less Haskell. However, I think the complexities of C++ templates might have been easier to tackle and understand with at least pointers to other ways it could have been (and has been) done. If nothing else, citations of alternative approaches would be a useful source for the motivated reader. As it is, it doesn't even deal with differences between C++ implementations - it doesn't even list GCC in the index.
All in all, though, C++ Templates: The Complete Guide is exactly what it claims to be. It's an in-depth treatment of C++ templates and how they work. It isn't a cookbook for practical applications, nor is it a guide to further in-depth exploration of parametric polymorphism. But it is definitely a handy reference for the working C++ programmer to have on her shelf. If you're a working C++ programmer, I'd recommend it. If you aren't, you might want to pass on this one.
You can purchase C++ Templates: The Complete Guide from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
But then you loose the flexibility of multiple inheritance if everything ultimately has a single parent. It's always going to be a trade-off. If there was "one right way" to do everything, we'd all be out of jobs within the next decade :-)
Hi, have you ever heard of the STL?
/syle
I have used C+ for several years, and love its abilities to model layers of belongingness with its OO principles: but I assessed templates as evil and have never used them. My understanding is that the template mechanism is like a super #define, that is, the compiler spawns multiple implementations of templated classes.
The seemed to me a recipe for bloat/cache thrashing/ugliness. I did not see bloat addressed in the review. In my reactionary way I continue to believe my prejudices.
Does anyone who has used templates have anything to say about templates and bloat?
Java's everything-inherits-from-Object model is annoying & sometimes rather ugly. There is a vocal group of Java programmers trying to add templates to Java, you should check it out before declaring templates an unnecessary evil.
Well, I'm going against my grain here (being a Java lover), but templates mean that you ensure cast.
For example, I make a stack in C++:
Stack bleh<int> = new Stack();
int i = 1;
bleh.push( i );
(excuse my syntax, I havne't C++'ed in a few years) and I have a stack full of ints.
If i use a java container:
Stack javaStack = new Stack();
javaStack.push( new Integer( 12 ) );
I lose cast. If I pop from C++'s bleh, I'm guaranteed to have an int. If I pop from Java's javaStack, I'm getting a java.lang.Object. I have to force cast and have a chance of a runtime exception.
That is one major reason why templates are a good thing.
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
Is this another book in their Professional Computing Series?
I've found several of them that I've read to be excellent references. They aren't textbooks, but they contain lots of information that is accessible and useable to people who write lots of code and want it to be understandable and maintainable.
I know a lot of people who are required, for their job, to write both Java and C++ code. Are templates really applicable to those developers? In other words when you switch back and forth between the two frequently do you resort to the lowest common denominators of the language instead of using more "advanced" aspects?
My J-Developer friend was just telling me the other day how he longed for templates in Java.
--------
Free your mind.
You are forgetting one of the biggest advantages to generics such as templates, speed. When templates are used much if not all of the binding is accomplished statically at compile time, when inheritance is used much if not all of the binding occurs at runtime. When you use inheritance every call to a virtual method requires a lookup to the vtable, this overhead is non-exsistent in templates. This is not an issue if you are writing bloated desktop apps in Java, but embedded or system-level applications demand the highest speeds possible.
This is a legitimate question, and shouldn't be modded down. It warrents a good discussion on the topic of templates (which is, in fact, the topic of this review).
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
a fairly well thought out, educated, concise, relevant comment on the article..
WHO ARE YOU AND WHAT HAVE YOU DONE WITH SLASHDOT!?
yeah, but then you would have to do all this awful casting everywhere as you have to do in Java. TEmplates is a much more elegant solution IMHO.
Java is supposed to have templates from 1.5 anyway IIRC, so you'll have a choice then.
if (!signature) { throw std::runtime_error("No sig!"); }
A post like your's is the reason I posted. I wanted to see some varying opinions on the subjects. Thanks for falling into my trap. LOL!
1) Why do you find Java's object model annoying/ugly?
2) Why in the world would a group of Java programmers want Templates added to the language? It's easy to find out what Class an object is in Java. I never have typecasting issues.
What idiot modded this down? It's a genuine question...
Templates are great because you can program generically but take none of the speed hit of using inheritance and virtual function calls.
Whereas in Java you get such abominations as an array of Integer objects, C++ templates allow you to have an array (or vector) of ints.
In theory, Java's approach looks nicer. But then in theory Java should not have atomic types (int, byte etc) - and yet we're stuck with them for performance reasons. Templates are all about performance.
One of the major strengths of templates is to avoid exactly the situation that Java everything-from-Object inheritance causes in collections.
In other words, this code:
gets boring really quickly. Templates in collections saves you all that downcasting.In fact, it's so useful, it's appearing in Java in JDK1.5, courtesy of JSR 14.
But far beyond convenience when typing, the important point is that using templates or generics in collections turns the typesafety of collections into a compile-time check rather than a runtime exception. Which is a Good Thing.
If the only thing you're ever pushing on the stack is an Integer, then there is no risk of error from casting back to Integer when you pop off. To get an int then of course you can use Integer.intValue(). Slightly annoying and roundabout, but I've never had a casting problem when I always knew why type of data was going into the structure.
check out this extension:
http://www.cis.unisa.edu.au/~pizza/gj/
if (!signature) { throw std::runtime_error("No sig!"); }
Templates are only bloat when misused. In many cases, your options are to write a template, or cut-and-paste then modify a class/function over and over. You can also write classes that only have template members, so if most of a class is the exact same no matter the data type, you're fine. Templates also let you do things you simply can't do in this low level of a language otherwise (and many high level languages also don't allow) - take a look at what the BOOST library does. There comes a point when you have speed/efficiency/code-size vs. taking 6 years or 6 weeks to code something, and with today's hardware, the later is usually the best choice. Also, templates can be used to generate data, not just code, so where you might have before needed a function call in order to compute a value, a template could turn it into the actual value at compile-time (look at how modern games use templates to generate sin/cos/tan/etc. values for constant inputs).
I should have completed my thoughts before posting.
I wanted to conclude that the only way to ensure cast with java's is either
A.) Write a wrapper around the collection/map (where the accessors cast to the object, eg:
public void setStack( Integer input )
).
B.) Use arrays
The big downfall of java.lang.Object is unsure cast (so you have to be careful with your coding, and follow good polymorphic code styles).
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
You imply that inheriting from a base class is always better, but that's not necessarially true.
The guy(s) who wrote the STL Containter Classes did it that way (using templates) because they think it's better than having all the objects inherit from one base. It's a style of programming called Generic Programming.
The basis of Java is dynamic run-time polymorphism. Using templates and generic programming techinques most run-time polymorphic algorithims can be reimplemented using compile-time polymorphism, which is much faster. That's what the C++ STL container classes are. That's where the power of templates are.
p.s. I've looked at the book in the article and I would describe it as an entire book of special cases. It explains things like recursive template definitions. Things that are so confusing that I try and stay away from most of them. They make code un-readable to anyone but a template expert. Then again, I don't write templated libraries either.
Aw crap, ninjas!
well, because they really want to perhaps? you're not the only java developer and taste differs.
See this:
http://jcp.org/en/jsr/detail?id=014
if (!signature) { throw std::runtime_error("No sig!"); }
If the only thing you're ever pushing on the stack is an Integer, then there is no risk of error from casting back to Integer when you pop off.
But you can't be absolutely sure. Yes, in practice, we generally assume everything is ok, and we rarely have trouble, but when you get down to reuse things can get hairy (hey, the compiler isn't stopping me from adding my String into the Stack, so why not?).
The nice thing about Java to counter, though, is reflection. You can always check the class type and methods before casting.
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
This ultimately comes down to a decision of *when* do you want to handle the "type" issue.
In Templates, you decide up front.
In Java, you handle the decision when you actually use the java.lang.Object object. In your example, adding the simple "if" check with the code ".getClass().getName().toLowerCase()" to determine you're truly using an Integer would eliminate any runtime errors whatsoever.
I have never had a Java runtime error over typecasting issues. If something unexpected is in the Container, I throw an exception or bypass the value entirely. There is no excuse for having a typecasting issue in Java when you can check the object's type.
Templates only seem to be a necessary evil in OO languages that don't ultimately inherit all objects from one object.
This is a naive view that circa 1992 C++ collection class designers used to share. The OO-container strategy was proven to be slow and not type-safe. The designer of the C++ Standard Template Library (STL) Stepanov does not even believe in OO programming - he calls OO a hoax. I personally would not go that far, but I appreciate that OO and generics are completely independent concepts. Furthermore, an STL map or vector working on types directly is much more space efficient than any OO container-based approach because each object contained does not require OO overhead. Indeed, native types (ints, doubles, etc) in vectors can be nearly as efficiently stored and accessed under STL as would C style arrays. No need for awkward casting or unnecessary and slow boxing/unboxing. To sumamrize, C++ templates and the STL fit in perfectly with the C++'s "zero overhead" principle.
Microsoft just doesnt't compile them properly and it is very frustrating to all C++ programmers. Chances are, if you write C++ in the commercial world, your company has the very wise policy of making sure you stay roughly within the capabilities of the most popular compilers. This basically means you can use STL's vector, string, and list, and a pretty small collection of others. This, in my opinion, is a programmer's tragedy.
Utility C++ templates allow it to create and use some amazing things. I personally rarely write anything but the most simple ones, but when I'm allowed, there are huge libraries of amazing template classes. I learned ML at some point, and I remember the wonder when I happened upon the tuple template class for c++. With the exception of the fact you are forced to carry the type around (as a typedef of course), it works exactly like an ML tuple, a tool I came to love in my short time with ML. Someone simply wrote the template, and it was in C++ too! (a tuple is like an STL pair, but has an arbitrary number of members, set on construction).
Of course, even VC7 doesn't compile it. If you work at Microsoft in the Visual Studio area, PLEASE tell them to get standard compliant already! Yeah yeah templates can be slow to compile, but give us the option at least!
Your signatures belong to me.
Being fresh out of college, we used linked lists like they were going out of style. When I began work, I found out they were! Using an STL template and container serves as a good replacement for linked lists and other annoying data structures. I rarely use arrays anymore, I would rather use a vector or map. my personal preference, maybe because I hated linked lists and malloc arrays we exhaustively used in college.
100% Insightful
Thanks for the link. Please understand that I'm not refuting their decision to request Templates, I'm just wondering why they want it.
I'll study the link you provided.
Peace.
There is an interesting use for templates in 3D vector math:
http://www.flipcode.com/tutorials/tut_fastmath.sht ml.
It's a kludge, but it provides some real performance benefits.
OK. Could someone please offer some informed comment on the following. (thanks in advance).
If I template a two-argument function in C++ to (e.g.) compare two instances of a class for equality (using the == operator) and print them to an ostream if they fail to match (using the template was actually a class which manipulated objects which derive from a "Listable" interface.
Can I just point out that as well as people who don't program in C++, "C++ Templates: The Complete Guide" will also be of limited interest to those who can't read, as well as those who can but read only Cantonese, not English. It is of limited use for those looking for a guid on changing the timing belts in '98 Pintos, and as a guide to the wines of the Alsace region it is sadly lacking. Dr Aloquin Samovar reports from the Naval Hospital that the book is not suitable for use by transplant surgeons as a temporary heart.
~~~~~ BigLig2? You mean there's another one of me?
Just like macros can bloat your code, so can templates. If you put "real" code in templates, it will be duplicated; however, consider that you would have probably had to write it anyway, and having template instances is FAR better than having cut-n-paste code. STL instances can get pretty big because they have lots of memory management code in there and type-specific operations; this is good because it gives you type safety and proper element assignments. You can implement it another way, but you have to sacrifice something. Either it is type safety (like Java does with its containers), or correct element handling (escuse the shameless plug for my own ustl library).
That's too bad, because 9 out of 10 times when I've had troubles with templates it's because of differences between C++ implementations. Beautiful, well thought out, intricate standards-compliant examples are useless if I can't actually get them to compile with my real-world compiler!
The book I'm looking for is the one that gives me real-world recipes for getting around bone-headded compilers. For example, there are at least 3 different ways to declare templatized friend functions depending on the compiler. Only one is correct according to the standard, but the standard isn't worth a whole lot to me today if the compilers I'm stuck using don't follow it. And likewise, an advanced templates book isn't of much use to me today if the examples won't compile on my compilers.
First, there are some significant errata (and a lot of minor typos). Get the errata list and the code for all of the examples from one of the authors at his website. Second, some of these techniques depend on features that aren't yet available in many compilers. Don't expect them all to work yet. They do discuss that in the book.
With that said, I'm not sure that I would have rated this book a 10, but it's close enough that I'm not arguing. It is not a light read, nor should it be. This book and Andrei Alexandrescu's Modern C++ Design have convinced me that C++ templates are much more powerful, useful and complex than I realized. In fact, if I hadn't read Alexandrescu's book first, I wouldn't have thought C++ Templates was missing anything. These two books should be on the shelf of anyone who wants to use the full power of templates.
The net will not be what we demand, but what we make it. Build it well.
I already conceded this point somewhat in another reply.
Its not that I always have trouble with it, its more when dealing with another persons code and reuse that you are never sure.
BTW - Using "instanceof" is a lot easier than ".getClass().getName().toLowerCase()". Even easier would just be to catch the ClassCastException, report it (or swallow it), and go on (or get the next value).
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
Where can I get the tuple template you speak of?
I'm interested since I regularly work in C++ and Erlang/O'Caml/SML.
This book is about defining and using your own templates, not using STL.
Just like a book about OO design has nothing to do with a book about the MFC.
I don't need no instructions to know how to rock!!!!
Feel free to write a better language yourself.
Actually, there is a Java Specification Request to add generics to Java, which is essentially adding template capability. The proposal is JSR014.
With a Java Developer Connection account, you can try a prototype compiler with this capability. It claims to generate code that can run on a standard 1.3 JVM.
Of course they aren't always necessary, but sometimes they are down right handy.
Why in the world would a group of Java programmers want Templates added to the language? It's easy to find out what Class an object is in Java. I never have typecasting issues.
:-)
Again, I'm going against the grain. I'm a giant Java supporter, but your statement is rather arrogant.
Why should they add garbage collection? I never have problems writing destructors!
Perhaps you don't work in a large enterprise setting, but sometimes we have standards that require heavy typecasting, and the only good way to do that is passing around arrays (and GOD do I hate arrays when we have collections!). Templates would solve the issue by keeping a heavy typecast, but at the same time, keep collections. Everyone is happy!
Why do you find Java's object model annoying/ugly?
Some people just hate java. Its either the object model, the speed (which isn't an issue anymore), or the 'memory bloat'. Ignore those comments, its just angry coders that aren't up to speed with java (or coded in it once when it was java1.1).
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
Checking type and methods is a poor substitute for enforcing that only the correct things get put in the collection in the first place.
Here's the problem I have with books like this. The examples are things that already exist.
C++ (or any OO) books that take you step by step through creating a class CShape, then sublclassing CBox, etc etc... Yeah, I get the principles of inheritance, but trivial examples CShape, CBox etc no doubt already exist in $LIBRARY if they're of any use.
So my question is, do the examples in this book just spew out stuff thats already in the STL?
I find that tends to have people reinventing the wheel, writing their own templates for say a stack or queue, because the book taught them to do so, even though it already exists.
And what of namespaces. Those things piss me off.
I don't need no instructions to know how to rock!!!!
Can I just point out that as well as people who don't program in C++, "C++ Templates: The Complete Guide" will also be of limited interest to those who can't read.
Which kind of categorizes one with the other
*duck the flamethrowers*
Exactly. If there is one thing Java lacks that is more strong typing in its Collections classes. The collections classes are arguably one of the best things that have happened to Java in a long time, but the fact that you have to use casting so often really leaves a bad taste. C++ templates definatelty rule in that area (coupled with operator over-riding, which I also think is super cool).
Name one compiler that is 100% C++ standard compliant.
GJ is the old implementation of Java Generics. It has since evolved into JSR-014. Sun has a prototype implementation of a compiler that supports generics, and there's even an entire forum for discussing Java generics.
What a fool believes, he sees, no wise man has the power to reason away.
IMHO, is that a book like this needs to exist. Templates are *way* too complicated for something that is supposed to reduce complication.
I am not a C++/Template god like many of the /.ers are,,, but if I recall correctly, once you set the type for the templated class, that entire class can only accept that one type.
I have constant need in Java to store all kinds of objects in Hashmaps. Templates would get in the way big time for me.
I rarely see this in template discussions but the thing I love about templates is the ability to do template "closures" for lazy evaluation whereby instead of returning the result of a function, you return an object which represents the application of the function to those arguements. This object then gets cast into the final resultant object.
Why?
Lets say you are concatenating a bunch of strings. Normally, you would create the concatenation of two strings, then concatenate the third, etc. Depending upon your string implementation, you could reallocate the string results many times.
However, with template closures, the concatenation would return an object which pointed to the two objects that were to be concatenated. Then the second concatenation would point to that object plus the next string. When the entire object was finally actualized by, say, setting it to a variable or as a function argument, then it would create the final string. It could then gather the lengths of all the strings, create a single result string, and then copy everything into it.
And it wouldn't look any more complicated than:
string a = b + c + d + e;
or whatever and it would still be optimally efficient.
The big downside is that error messages are all but useless.
Synergies are basically awesome, and they're even better when you leverage them. -PA
Greg Comeau's is pretty damned good. Any compiler built off of EDG's (Edison Design Group) stuff is going to be compliant (including the export keyword)
I agree with you, but the concern being set forth by others is that because Java's Container Classes aren't templated, you can't tell what is being stored.
I have to check the type being stored in my code because I have need to store a wide variety of objects in Hashmaps.
if (x instanceof Number) {
Number n = (Number) x;
}
Now time how much slower it is...
What a fool believes, he sees, no wise man has the power to reason away.
Why bother.
This is one of the key strengths of C++. It provides two powerful abstraction mechanisms - runtime abstraction, throught the use of virtual functions, and compile time abstraction, through the use of generics (templates). The programmer can choose which mechanism is appropriate for the problem he is solving.
One big advantage not mentioned yet is that using generics as an abstraction mechanism causes errors in your code to manifest themselves at compile time rather than runtime - i.e. on your desk rather than your client's !
taste differs, what you might not like, many other people might find the dogs bollocks.
Fails to see what would be such a 'necessary evil' thing with templates for c++, on the contrary, I find it much more elegant with templates.
If you absolutely have to use a lib with a common base class in c++ you can always go and use MFC, they do just that.
if (!signature) { throw std::runtime_error("No sig!"); }
you should use perl, then you wouldn't have to worry about types at all :D
(just kidding)
Debugging heavily templatized code is thoroughly nasty. Names are mangled beyond recognition for anyone not using a 500 column display or lots of scroll bars. Stepping through code in the debugger often yields senseless results -- you often cannot see the source for the instructions being generated without manually tracing through the headers and looking for every overload and template body declaration. Templates thorougly ambiguate linker symbols. Templates slow compiles to a crawl, often adding tens or hundreds of thousands of lines to every inclusion of a given header in order to define the types it uses. With subtly improper use, templates can bloat code size astronimically and create horrendous execution bloat.
I don't know how many weeks I've lost to helping others debug or rewrite their code because they thought they would do something "clever" with templates and they ended up creating a maze. And bringing in third-party code with templatized interfaces has frequently required more time to debug and adapt than it would have taken to create the code anew.
If you're going to use templates, stick to simple container classes for now. Anything else should be considered theoretical research until the tools catch up. Let me repeat: development tools HAVE NOT CAUGHT UP WITH C++ TEMPLATES. There is no debugger available which makes templates as transparent as normal code, inline functions or even #defines.
And please save your first forray into templates for private projects. Don't inject your template experiments into code others are trying to use!
http://www.annexia.org/freeware/cpptemplates/index .msp
libguestfs - tools for accessing and modifying virtual machine disk images
Ah, looks like I'm sitting on old info, thanks for the link.
if (!signature) { throw std::runtime_error("No sig!"); }
in c++ this is done exactly as in java, it just that you have to explicitly set your common base class yourself, in java class Object is always there by default.
if (!signature) { throw std::runtime_error("No sig!"); }
It's a real shame if this book doesn't explain implementation details like this!
What a fool believes, he sees, no wise man has the power to reason away.
Inheriting everything from "Object" isn't good enough either... which is why Java 1.5 will have templates as well.
Often times you want the compiler to be able to do some type checking at compile time to make sure you can even call certain functions on certain objects.
OOP is ok... but it can't solve all problems easily and refactoring of old OOP designs is a huge pain in the ass sometimes. This is why there are technologies like Aspect Oriented Programming in existence. AspectJ is a good example of this and I believe it is available with the popular eclipse IDE.
VC8 is said to be quite std's compliant. Coming soon ...
There is no reason why you can't have multiple inheritance if everything inherits from a single base class.
C++ might have problems because it would have to use virtual inheritance which probably hurt performance. Eiffel has a base class called ANY which is like Java's Object class. So you can declare lists like LIST[ANY] if you want, but it also has genericity allowing you to declare your list as LIST[INTEGER].
To get a good background in OO concepts, like generics (templates in C++), Bertrand Meyer's Object-Oriented Software Construction is what you need.
It's practically required reading to understand OO, and it explains, among other things, why a language with a single eventual superclass (like Eiffel, as well as Java) also needs generics.
And, as much as I reminisce about C++ and remember using the STL and other templates (my first taste of generics), its implementation of them is pretty bad. So, don't think that it's an "evil" necessary or un, having only seen them in that language.
"Whatever can go wrong, will." --Finagle's Law
What, like Java? The most commonly used types in Java (int, bool, maybe float) don't inherit from Object.
You can manually put them into wrapper objects like Integer which do inherit from Object, but you could equally well do that in C++ by defining a single Pointer class which wraps a pointer-to-void. But of course in C++ you wouldn't want to, because you can have type-safe containers without such shenanigans.
-- Ed Avis ed@membled.com
For an excellent overview of generic programming in C++ and the STL in particular, check out Generic programming and the STL, written by Matthew H. Austern.
It's definitely the best C++ book I've read so far.
However, it's nearly always fatal to mistake a tool (in this case, templates) for an end in itself (a functioning, maintainable codebase). No programming technology, be it HLL in general, objects, inheritance, or even templates will replace the need to think intelligently and make sound engineering decisions. You cannot build a skyscraper without the proper knowledge, no matter how excellent your hammer is.
The company I work for is among the few remaining who produce large-scale Windows products written entirely (ok, 99.9%) in C. My work is in a totally different world than the object oriented people, yet I still manage to accomplish everything an OO programmer could do. The secret here is not cute little language features, but discipline and correct design.
IMHO, templates do not deserve a book quite this large. Clearly, the author has had enormous experience in various situations, and knows how to solve all kinds of problems with templates, BUT -- remember the famous words passed down from people wiser than ourselves: "When all you have is a hammer, everything starts to look like a nail." Make sure the hammer isn't the only thing in your toolbox.
For those not too familiar with templates (personally I learned all from Stroustrup's book), there are a lot of interesting and sometimes quirky features.
One of the best examples perhaps is the STL vector class, which has three implementations. An implementation for a vector of booleans (made specifically to save space), a vector for any type of pointer, and then the generic vector class that covers anything else. Templates have some powerful features.
Unfortunately, there's still some things that need to be done in the compilers. Certain compilers in the past have had problems with them (hopefully they're fixed now), and errors in templated code are cryptically reported -- which always confused me. If compilers mangle a name to get the templates to compile, why can't they unmangle the name when reporting errors?
------------------
Lailyx -- Karma's overrated.
I work in a Java shop that has inherited a huge legacy C++ system, meaning we still have to do a lot of maintenance in C++. In order to get by coding in C++ with the same ease as we do in Java, the STL is a necessity--especially when working with collections.
It is tempting to think of templates as just a fancy way to make a list of addresses (i.e. list) without having to do any casting. But templates let you do much, much more than that- It adds another tool to the programmers' arsenal by allowing him/her to decouple different parts of a program in order to improve its design. This new technique is called "Generic Programming" and C++ programmers like to think of it as being "orthogonal" to other ways of programming.
//y is now equal to 6
//i and iend are "iterators"
The first dimension of program design is to break code into procedures that can be called from several different places cleanly and transparently. This is what C and procedural programming made possible.
The second dimension is to have a type system that can channel the program to the correct code indirectly, either dynamically through OO polymorphism or statically through function overloading. This was what object-oriented programming and early C++ made possible.
The third orthogonal dimension is generic typing, or templating- Using this technique, new computer code can be created in a safe manner during compile time that allows abstractly-written pieces to be stuck together arbitrarily as needed to generate new code. All of these pieces have to fit perfectly in order for the compiler to accept it. If the pieces don't fit together perfectly, the programmer has many types of "glue" available (such as function adaptors, or iterator adaptors, etc.) to make them fit perfectly. If the glue isn't 100% perfect, the compiler lets you know and you can correct it. It can be a beautiful way to program if done correctly!
It also lets people program in a "functional" style, which was originally invented by LISP programmers, and is a great way to glue together abstract objects with abstract alorithms, without having many unsafe local variables. An example is "currying", where a function taking two parameters can be changed to require only one:
int multiply(int a,int b)//a function that multiplies two numbers
{
return a*b;
}
int(*x)(int)//x is a function that accepts only one number!
x=boost::bind(&multiply,2,_1);//set x equal to a newly created "version" of the multiply function that requires only one number- A function requiring 2 numbers now only requires one, without a local variable needed!
int y=x(3);
Another functional programming principle that is now possible is to write all your functions to use iterators, which are basically pointer-like objects that can point to anything: lists, arrays, stacks, almost anything! So to multiply all numbers together in an unknown(!) data structure you can write:
templatemultiply_all(T i,T iend)
{
T::value_type x;
while(i!=iend)
x*=i++;
return x;
}
If you begcome comfortable with thinking of all your data manipulation tasks in terms of iterators and use templates, a whole new world of programming techniques opens up to you!
You can use class introspection in Java to find out its proper class, it's part of the polymorphism by dynamic binding of runtime procedures design of the VM.
Or, you could use Objective-C, ala NeXTSTEP, where the generic pointer id always knows that the object type, and therefor never downcasts to the root object (Java was based in part on Objective-C). The nice thing about Objective-C is that unhandled exceptions aren't volatile (well, unless you end up trying derefrence a null pointer). In either case, yes, C++ templates are probably a great degree faster, but then again you loose all the dynamic features of a proper runtime system (so then you'd have to declare your methods virtual, which would end up causing your C++ app to run slower, but with the added pain of templates when you're using the STL).
The worst part about Java is its masochistic typechecking system. It's got all of these nice runtime features, but the compile-time typechecker really stands in your way as far as accessing this backend power.
Technically, you should be able to put it in the .cpp file, as per Stroustrup's book. gcc does properly implement templates (I should say, does not fully implement), but if you use something like Sun or Microsoft's compiler, it works correctly. Note that this is not an endorsement of Microsoft's compiler.
You forget (or have never seen) template methods. std::swap(a,b), for example, swaps the values of two 'things' and can be specialised to handle 'things' that need more work than the standard 'assign a to a temporary, assign b to a, assign the temporary to b' mentality. Templates are not just for classes but for methods too.
(big apologies for the 'things' bit ... early evening ... long day ... brain tired!)
If you want to be able to recognize what is the truth and what are lies (more lies) with Sun's J2EE and Microsoft .NET proprietary frameworks (however, they have and will have place in computing) study Standard C++ with the STL. Just reading Bjarne Stroustrup's interviews you will avoid shortsightedness and you will learn much more about computing then reading anything else.
Anyway, if you want the exact class test, it's better to write "if(x.getClass()==Integer.class)" and compare Class objects instead of dealing with Strings. Either this code or the instanceof code will be more robust and faster than the original code.
Exception handling is not the way to go to handle casting issues, unless it truly is an exceptional or unexpected condition that the cast will fail.
What a fool believes, he sees, no wise man has the power to reason away.
Typesafe Collections are a good thing, agreed. But are they a big deal? I can't recall a bug thats bit me in the past three years with the Java collection of Objects model but I recall vividly the pain of developin with C++ templates, the bloating in apps, slow builds, and painful debugging.
a decision of *when* do you want to handle the "type" issue.
Not just *when*, but also *who*. Or actually, *what*.
With a mechanism like templates, type checking is accomplished by the compiler, not the programmer. That means no extra statements in the source to bulk up the code, no extra conditional checks at runtime to slow it down, and most importantly, no opportunity for a human programmer to forget some of the checks.
That is the fundamental difference between a C++ STL vector, and a Java Vector which happens to only contain Integers.
An additional problem with the Java Vector (and something that'll be fixed when templates are introduced in Java 1.5) is that it can't contain things which don't inherit from Object (like int and float).
(Note that if a compiler is very smart, it is theoretically possible for both methods to be equally efficient at runtime. But that degree of optimization is rare even today- and depending on the class linking style, it may be impossible for the compiler to get all the data needed to optimize like that.)
but what do i know, i'm just a model.
So, instead of void Sort(int array[], size_t count) { ... } to sort an array of ints, you have template <typename T> Sort(T array[], size_t count) { ... } and the means to define a function that can sort an array of anything, with complete type-safety. Naturally, this generates a Sort function for each kind of array of things you need to sort... hmmm, there's room for improvement, no?
If you don't get the "there's room for improvement" part, and use templates to get nice type-specific varients of common functions, you will get code bloat, and that is one of the things that give templated-code a bad reputation. But, we're Slashdotters, we're smarter than that.
Recalling our C days, we immediately code void Sort(void *array, size_t count, int (*compare)(void *, void *)){ ... } where we pass a generic array pointer, and an additional pointer to a function that knows how to compare generic elements -- the specific call will then be something like: Sort((void *)pFoo, count, (int (*)(void *, void *))FooCompare). Gee, where did all our typesafety go? [Java programmers who are otherwise typesafety puristis grind their teeth at this point].
If you can imagine a generic implementation, you can combine the best of both approaches: hiding the type downcasting inside the generic templated definition:
inline void template <typename T> Sort(T array[], size_t count)
{
genericSort((void *)array, count, (int (*)(void *, void *)SortCompare<T>);
}
and for every array of type T you need to sort, define a int SortCompare<T>(T *arg1, T *arg2). (You could, alternately still pass that function to the generic sort routine, if you had different comparison functions for the same types of data (say, case-sensitive and case-insensitive sorting, or lexicographic vs. ASCII text sorting, etc.).)
Note the inline declaration. This lets a smart compiler code the call to the generic function inline, avoiding a double function call. In practice, if the only thing you are doing is some type casting, no additional code is generated.
So, you still have the potentially dangerous downcasting, but you've encapsulated it inside a template definition, relieving the application programmer to have to worry about it. Does all this mean extra work? It sure looks that you have to come up with a generic implementation and then make a nice and pretty templated type-safe wrapper around it.
This is true, and well worth the effort for code that has to be robust and easy to use, particularly by others. Library writers know this rule all too well.
Of course, in a pinch, or when a generic implementation is not obvious, or known to be non-existent, or when a particulary implementation exists for some types of objects, you can punt and let the compiler generate multiple instances of type-safe code, without a generic back-end implementation, accepting the code bloat that results.
In the end, it becomes a matter of compromise and wise design decisions. Unfortunately, with choice, comes the effort to chose, and to chose wisely. It is the unwise use of templates that leads to their sometimes ill-deserved "code bloat" reputation. One of the differences between the skilled and less-skilled programmer is the ability to make these choices correctly and quickly, leveraging the language features that let the corresponding design decisions be put into practice.
Other related C++ topics would include the notions that "multiple inheritence leads to slow code," "exception handling and run-time type information have high overhead". Again, one has to weigh the advantages offered by these techinques against the skill needed to use them wisely, and the performance penalty paid. I'll let someone else chime in now.
You could've hired me.
Nice to see the example using the boost library. That library rocks! The Lambda library stuff is very cool as well.
Later in the book, on template metaprogramming etc, there are lots of concrete examples. Perhaps the reviewer didn't read that far?
True, the book deals exclusively with C++. But contrary to what the reviewer states, it deals extensively with differences in C++ implementations. Whether or not one particular C++ compiler is listed in the index is not a very good judge!
Reading his last paragraph, I am sure now the reviewer did not read all of the book. It is not written in "cookbook" style, but for sure everyone reading the book will learn and discover new ideas for template design that they didn't know before. And the capabilities of parametric polymorphism are explored in detail, with quite large sections on how they could be extended (and possibly will, in the next C++ standard) to make some types of programming easier.
In short, this book is a mix between an academic treatise (it encapsulates practically all that is currently known about the C++ template mechanism), and practical guide to writing your own templates.
It's probably something to do with the 'export' keyword. Microsoft's C++ compiler simply does not support it. .h and the implementation in a .cpp as you normally would, say with a class. There are ways around this, but they suck.) This is because every time you make use of a template, the compiler needs access to its implementation details. See the chapter on templates (13, I think) in 'The C++ Programming Language', 3rd ed, Bjarne Stroustrup.
The problem is that you cannot have a template definition seperate from its declaration (ie, you can't put the prototype in a
"Dying tickles!" -- Ralph Wiggum
Comeau C++ is standards compliant. Most compilers based off of the EDG front-end are very compliant. This includes Intel, Comeau's and SGI's C++ compilers. It does not include MS C++ 6 or Sun's C++ compiler, and look at how standards-compliant those are (on the other hand, Borland's compiler is quite good and it's not EDG-based).
I'll pick up a copy as soon as a debug my long 'Hello, world!' app. Man this thing is a monster, it takes up about 1KB! I think I can shave some off, I'll leave off the ' endl;' and maybe delete some white spaces...
Spirit has to be seen to be believed. Basically you contruct a parser which looks like normal extended Backus-Normal Form (EBNF) but the source you write is 100% C++ source code - not run through a preprocessor:
struct calculator : public grammar<calculator> {
template <typename ScannerT>
struct definition {
definition(calculator const& self) {
expression = term
>> *( ('+' >> term)[&do_add]
| ('-' >> term)[&do_subt]
);
term = factor
>> *( ('*' >> factor)[&do_mult]
| ('/' >> factor)[&do_div]
);
factor = lexeme_d[(+digit_p)[&do_int]]
| '(' >> expression >> ')'
| ('-' >> factor)[&do_neg]
| ('+' >> factor);
}
rule<ScannerT> expression, term, factor;
rule<ScannerT> const& start() const { return expression; }
};
};
This is truly a testimony to the power and expressiveness of C++ operator overloading and templates.
As an aside, Perl6 is slated to have lexer/yaccer rule syntax built into the language itself. It's really an exciting time for users of computer languages.
if (!signature) throw std::runtime_error("No sig!");
The template version would give a compile-time error instead - type-safe and no need to to runtime error handling!
quote:Templates only seem to be a necessary evil in OO languages that don't ultimately inherit all objects from one object.
Multiple inheritance doesn't depend on all classes having a same base type. This gives you more flexibility in designing a set of classes. I should have made this clearer :-) Thanks for pointing this out so I could clarify it.
I will probably buy this book.
:) You basically create a class without knowing what the parent or the child will be. The advantage is, that it allows for quick and modular implementation.
...
,but I think it gets the point accross. For a good use of these misins, look for 'heaplayers' on google (though the code is a bit buggy by times, but since everything is working via template instantiation, it's hard to debug and bugs only pop up when the become instantiated.). It would be nice is this is covered :)
I started off with templates (when I moved from C to C++ for system level exploration) and found them to be an annoying evil for the restrictiveness of void use in C++ as compared to C.
However, I had to come along when I discovered mixins
A small example. A house is built from a cellar, a number of levels and a roof.
In order to implement a 1-level house you define:
class SimpleHouse<Roof<Level<Cellar> > >{};
if you want a more levels
class HighHouse <Roof<Level<Level<Level<Cellar> > > >{};
That's all folks, methods etc, defined by the template instantiation,
This example might be pretty silly
What I do want to know, is what exactly this is doing to my code bloat X)
Genius doesn't work on an assembly line basis. You can't simply say, "Today I will be brilliant."
I use she because women (and some men!) get all offended if I use "he" as a generic pronoun. I couldn't care less myself, so fine, have it their way. Besides... ladies first! At least when it's this easy. I don't think most people have mental images of every word they say/hear. Otherwise, how can you stand walking around at work hearing things like "you screwed my PC", "this code kicks ass" and "I have to remove all the bugs from this piece of shit today"?
The point is though, with templates the compiler would not have allowed you to add an object of incorrect type to the container in the first place.
Templates programming is great if you want to avoid dynamic memory allocations, as for example in real-time applications where dynamic memory allocations cause non-deterministic performance.
At clemson university robotics group, we created a generic robot control platform based on exactly such advanced C++ concepts. Take a look:
Robotic Platform]
And I would add, the need to do lots of casting (as opposed to simply calling a virtual function on the base class object) is a sure sign of a screwed up design.
Sometimes using templates does generate vast amounts of code. But guess what! Sometimes you want vast amounts of code. Templates allow you to build complex algorithms that get bound together at instantiation time. You only have to write the small pieces and the complexity gets built by the compiler for you. You can end up with a usefully complex piece of code that's easy to develop and easy to maintain. Without templates in C++ you have to resort to subterfuges like macros to build complex pieces of code at compile time.
Doesn't it make you feel good to know that our freedoms are protected by politicans, lawyers and journalists.
...of your code into the compiler making the run time faster. Here's an extreme example of what I'm talking about.
Doesn't it make you feel good to know that our freedoms are protected by politicans, lawyers and journalists.
Here's a simple way to do it in a language that's almost like Java: Stack mine = new Stack() /Object_must_be=Int;
(the "/" means, "here are the qualifiers to the code I just wrote"). In this case, the /Object_must_be=Int means that everything going it, and everything coming out, must be an int.
The generated code remains the same: it's just a compiler check; that check will fix most of the problems with the Java "Stack" (etc) classes that the original replier mentioned.
"All" that has to be done is mark the object up a little. We know, in java, when a method is a general one because it takes in or passes back an Object, so we don't generally need to mark up our original class.
And heck, in debug mode, it can even be a run-time check too; we can even make it a run time check all the time.
Want a sig like mine? Join ACM's SigSig today!
www.boost.org
The documentation for the tuple library is here
Templates in C++ go much beyond typesafe collections. As an earlier poster commented, in technical circles it's referred to as "parametric polymorphism". For the layperson, you can think of it as a form of specialized code generation.
The best example of how much bigger they are than typesafe collections is the use of templates for traits and policies. Take the classic reference counted smart pointer, which usually looks like this:
SmartPtr<int> i_sp = new int(5);
cout << *i_sp << endl;
What about the question of whether SmartPtrs should be allowed to hold null pointers? Maybe in some case it's appropriate, but in others an exception should be thrown if it's attempted. Rather than having two different SmartPtr implementation, you add a new template parameters, the OwnershipPolicy type. The SmartPtr author than provides types like AssertCheckStrict and NoCheck. So then your code looks like this:
SmartPtr<int, NoCheck> i_sp = new int(5);
SmartPtr<int, AssertCheckStrict> j_sp new int(6);
This example comes from Alexandrescu's Modern C++ Design, and his Loki framework.
In other words, you better hope that your testing is good and that the bug that causes a string to get put on the stack doesn't only appear in a rare set of conditions.
The cake is a pie
I've heard Templates used in multiple ways, one being parametric polymorphism, such that you have the following:
// works // works, notice no cast // compile time failure: add must pass a Product parameter
List productList = new List;
Product p = new Product();
productList.add(p);
p = productList.item(0);
productList.add(new Object());
The other way I've seen it used is to do 'loop-unwinding' where you have a loop that at compile time you know the iteration bounds, and it will remove the loop and duplicate the looped code for each iteration.
In the Java space, 'templates' are not realy the goal, rather 'parametric polymorphism' is because it can lead to faster execution (no casts at runtime, although currently no implementation supports this because it would require bytecode changes, the current generics compiler just hides casts), and also more explicitly define what collection classes are declared to contain.
A lot of people have argued that they have never created a collection object (like ArrayList) that they accidently put the wrong type into it (or maybe they've done it once _ever_.) However, if you are working with a service library that someone else wrote that returns collections of things, you have no way of knowning what the collections of things contain without referring to some documetnation. Parameterized types explicitly declare what the collection contains, so you have a tighter integration with what the code is doing and documentation. (everone here infavor of self-documenting code, raise your hand).
-Chris
Also, a reference-counted smart pointer won't impress a Java coder such as the parent poster, since garbage collection makes it irrelevant.
If you can imagine a generic implementation, you can combine the best of both approaches: hiding the type downcasting inside the generic templated definition:
inline void template <typename T> Sort(T array[], size_t count)
{
genericSort((void *)array, count, (int (*)(void *, void *)SortCompare<T>);
}
So, you have just slowed your sort template by an order of magnitude, since you use a function pointer to compare elements, something that would be probably inlined by the original template.
Best of both approaches? I don't think so...
Apparently, the evil one is branching out...
On the flip side, STL leads to massive code redundancy and scattered data locality. In real-world use, STL tends to be slower than generic containers dealing with void pointers and passed accessors for the sorting/hashing or a generic base type with virtual functions for the sorting, etc.
IMHO, STL's only real advantages are its offering of standardized representation for many generic algorithms, and the way it's renewed some otherwise bad programmers' interest in the same. It's more of a memetic advance than a technological one.
Basically the current bool vector should be depreceated as soon as possible.
When the experts cannot figure out how to use the export, that tells you something. What is does is very subtle and complicated, and hardly anyone understands it. It appears to be a major C++ design mistake.
But you will have a casting problem as soon s your code intrfaces with mine.
:-) BOOM.
... with templates I had much more work to get your code make BOOM.
... think about it and you get my point.
As I hate template agnostic programmers, I put allways a wrong object into their "generic" data structures.
And when they take it
Hm
The above is just kidding
angel'o'sphere
Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
thats wrong!!
...
Using reflection:
if (x.getClass() == Number.class)
is exactly the same like your:
if (x instance of Number)
Its even exactly the same byte code
angel'o'sphere
Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
Yes, but I was addressing the use of templates to hide downcasting and still use common backend implementations, increasing type-safety. I briefly hinted that this does not add anything over the classic generic C solution. Obviously templates can help us do better than this, a lot better, for the reason you note.
In practice, we'd probably specialize Sort() for the types of interest:
void Sort(int array[], size_t count)<int>
{
InlineCompareSort<int>(array, count);
}
In fact, using type traits (see Alexandrescu's "Modern C++ Design"), we could have Sort use a SortImplementationTrait<T> class template and automatically generate an inline comparison or external comparison function version, based on the SortImplementatioTrait of the type being sorted (vis. SortImplementationTrait<T>>::Inline). That's probably what you were thinking of. If you want, I could flesh out the design for you (hint: Partial template specialization on the type trait makes it easier.)
But, that gets us far from the aspect of the original concern that I chose to address: encapsulation of downcasting within templates to enhance overall typesafety of code.
You could've hired me.
As someone who has had to use templated code in many a port, I would never ever advocate using templates. If you say that you need to use templates then you don't understand OO. If you say you actually like using templates well that you don't understand programming. If you say that templates work across compilers then you are insane!
As has been mentioned templates are evil, exorcise them from all code. Now!
Life is like gravity. It sucks you down.
Templates as a way of building code that can be instantiated for various types are great. Templates used as a general-purpose programming language suck. You create all the problems of LISP macros, and with far less debug capability.
You can put the implementation of a templated class into the cpp file IF it is explicitly instantiated.
Add the following to the bottom of Foo.cpp:
template class Foo(int>;
There is a limitation... you cannot instantiate Foo without adding an explicit instantiation for it. For internally used template classes, this is sometimes quite useful.
The real point is: if you're safe and do some type checking, you'll never have a problem in any situation.
Are you a troll or just a moron?
in terminus illic est tantum opes
public class TryIt {
public static void main(String[] args) {
Object x = new Integer(3);
System.out.println(x instanceof Number);
System.out.println(x.getClass() == Number.class);
}
}
Here's the output of running the code:
true
false
Here's the bytecode for the first test:
13 instanceof #10 <Class java.lang.Number>
Here's the bytecode for the second test:
22 aload_1
23 invokevirtual #12 <Method java.lang.Class getClass()>
26 getstatic #13 <Field java.lang.Class class$java$lang$Number>
29 ifnonnull 44
32 ldc #14 <String "java.lang.Number">
34 invokestatic #15 <Method java.lang.Class class$(java.lang.String)>
37 dup
38 putstatic #13 <Field java.lang.Class class$java$lang$Number>
41 goto 47
44 getstatic #13 <Field java.lang.Class class$java$lang$Number>
47 if_acmpne 54
50 iconst_1
51 goto 55
54 iconst_0
Now go compile and run that code yourself and use javap -c and look at the bytecode. Then read what I originally wrote again and come back with a more sensible response!
What a fool believes, he sees, no wise man has the power to reason away.
So what the fuck IS the book for, if not to learn about templates?
Sorry, the Microsoft VS 2003 (currently in beta for marketing reasons, though the code is really finalized) C++ compiler is THE MOST standards compliant C++ compiler you can get after Comeau C++. It supports every feature, with rock-solid stability, except for the 'export' keyword, which is useless anyway. And unlike Comeau C++ it can be used to generate real-world optimized code.
12 aload_1
13 instanceof #10 <Class java.lang.Number>
Of course x has to be pushed onto the stack before we can test if it's a Number.
The response to my challenge brilliantly demonstrated my point about reflection. It's way trickier than it looks! DON'T USE REFLECTION IF AT ALL POSSIBLE!!!
What a fool believes, he sees, no wise man has the power to reason away.
For sure. Actually, your sig encapsulates the advantages nicely:
if (!signature) throw std::runtime_error("No sig!");
The template version would give a compile-time error instead - type-safe and no need to to runtime error handling!
Only if the signature presence had to be determined at compile time. How flexible is that?
This whole compile-time vs. run-time error business is a red herring.
When you say getting an error at compile-time is better, you are just saying that C++ ensures that your program fits in the straitjacket that you made for it, ignoring the fact that you've made a straitjacket in the first place!
Making a stack which is "int only" is totally specialized. How are you "accidentally" going to write code that asks for something else, if your problem is so focussed that it only needs ints?
You really think that using strings by mistake is going to be a major source of bugs?
The real problem is that C++ operations are type-specialized at compile time. C++ compilers, for instance, don't know how to add numbers unless they know the type at compile time. In a dynamic language, the addition operator knows how to add whatever numbers it sees at run-time.
For every set of bugs that a compile-time error catches, there is a corresponding set of desirable program behaviors that become more difficult to explain to the compiler. That's why the whole idea of "design patterns" caught fire in the C++ world. These design patterns are like a phrase book translating your desire into the C++ language. If you have a more flexible language, you don't need a phrase book as often!
If you're writing production code then you don't want weird exceptions throwing up all over the place. I'd far rather make the straitjacket I want and then keep to it, than have a higher risk of my program barfing.
For example, with the Stack cast to int before - what if the stack definition is somewhere over the other part of the program, and one member of the team decides it should be a stack of vectors (or something), and your code to pop an int is in a very rare situation (so it may get missed in blackbox testing) ?
Well said. Let's not also forget that the template parameters don't have to be data types, for example they can be the bounds of some sort of collection - or even a flag for some function/class that looks much more elegant that #if .. #elif ... everywhere
if (Number.class.isAssignableFrom(x.getClass()))
I switched the Number.class and x.getClass() when I first wrote it, and actually wrote Integer.class instead of Number.class at first. Reflection code is not easy to get right!
Additionally, the instanceof test took about 40 nanoseconds and the reflection test took about 600 nanoseconds on my computer. Reflection code is about an order of magnitude slower, and about an order of magnitude harder to write.
What a fool believes, he sees, no wise man has the power to reason away.
I've never had any problem with Borland's compilation of templates. Have you given C++Builder a try instead of VC?
try the following:
1. code up something using STL classes other than the ones i've mentioned, and then try to do something meaningful - they just won't compile.
2. try virtually any of the moer advanced templates of boost.org, a great site for templates. VERY few lack the note 'won't work with microsoft'
Your signatures belong to me.
template void print_hello_world(void)
{
printf("%c%c%c%c%c w%cr%cd\n", a, b, c, c, d, d, c);
}
int main(void)
{
print_hello_world();
return 0;
}
-
Pointers, References and Values
-
Properly Managing Memory Returned by transcode() in the Xerces XML Library (really about refactoring)
-
Pointers to C++ Member Functions
Thank you for your attention.Request your free CD of my piano music.
Man.. i've been sitting here all day thinking how dumb those people were that screwed up their code cos they didn't preview , and then I do it myself :) Mods mod down my previous to 0..
Here's take 2: the bad template coder's Hello World
template <char a, char b, char c = 'l', char d = 'o'> void print_hello_world(void)
{
printf("%c%c%c%c%c w%cr%cd\n", a, b, c, c, d, d, c);
}
int main(void)
{
print_hello_world<'h', 'e'>();
return 0;
}
I was referring to the data stored within the STL vector or map being very space efficient. As for template code bloat - it's getting less so with modern C++ compilers. Furthermore, only the template functions actually used by the program are actually linked into the executable. Because STL does not use virtual functions programs using these templates can be highly optimized. Some compilers even share template methods between types if the type does not affect the generated code. However, I will concede that all this intense optimization does take a lot of compile time and memory. Some scarier template-heavy source files I've encountered using Boost have used 500 megs of RAM to compile under high optimization; but the final .o file size was very respectable.
If the signature presence had to be determined at compile time, this would be advantagous. But it does not neccessarily have to be so.
Life sucks, but death doesn't put out at all....
--Thomas J. Kopp
It's probably something to do with the 'export' keyword.
Not at all. Very few compilers support that. The problem with VC++ are many, but one of the major ones is that it doesn't support templatized member functions (at least not in VC++ 6).
A Government Is a Body of People, Usually Notably Ungoverned
G++ isn't 100% standards complient, but it's pretty damn good. It compiles almost all of Boost. That's more than can be said of Visual C++ 6 or 7. 7.1 is supposed to be better, but IIRC, it's still in beta.
A deep unwavering belief is a sure sign you're missing something...
Ha ha. Silly MS programmers with their Visual C++ 6.x. Either spend the money and upgrade to 7.0, or be a real man and use GCC.
A deep unwavering belief is a sure sign you're missing something...
"C++ Templates" isn't about using the STL. It's about writing templates, and how they work. It will let you understand how to build extensions to the STL, or how to design its successor, if you make the effort.
e s.txt, if I recall correctly.
My review is online at http://www.jamesd.demon.co.uk/reviews/c++-templat
What's extensive? I've got my code built on template classes for lists, sets and associative arrays and the main program is 100k lines. Compile times on an old 500MHz Linux machine with gcc are completely acceptable. Compile times on my even slower mac with CodeWarrior are a little worse, but still acceptable.
Debugging? Both platforms handle templates transparently. Especially CodeWarrior does a nice job in its totally integrated environment, but gdb ain't bad neither.
Bloat? Neither. Yes, a list of ints will generate exactly the same code as a list of long ints twice, but this kind of template generates little code, so that's a small price to pay for transparency.
I don't know how many weeks I've lost to helping others debug or rewrite their code because they thought they would do something "clever" with templates and they ended up creating a maze.
That's a good point, but it simply refers to bad design and/or programming. Templates do offer an extra way of complicating code, but it doesn't have to be that way. Multiple inheritance can be a similar drag, but simple inheritance almost never fails in helping write clean code. Are you going to argue that inheritance is therefore bad? Didn't think so.
No, I think templates are really, really useful, and I like them a lot better than the inheritance mechanism. Just keep the design and programming clean, like everywhere else...
Now that it's been shown to be possible, it's generally considered to be a bad idea. Since superscalar machines came in, loop unrolling can be a lose. Today, branches in tight loops are cheap or free by the second time around, since the branch predictor knows what happened last time. You get more cache misses with bloated code, too. Loop unrolling isn't the big win it used to be.
It's a matter of telling the compiler what you expect so that the compiler can tell you if what you expect is wrong.
It catches bugs.
You may be interested to know that there were many C++ container libraries that used "derive from object" and runtime casting long before templates were even part of the language. They've been dumped in favor of template containers precisely because template containers have advantages over them. I've used both, and I've also used both Java and C# containers extensively, and believe me, I'd rather be able to tell the compiler what to expect.
No, confusion between strings and ints isn't a major source of bugs...but when you've got a lot of different classes and a complex hiearchy it is a different story.
As for design patterns...I find your comments amusing given that the canonical design pattern book used the ultimate dynamic OO language, Smalltalk, in all its examples.
The cake is a pie
Also note that C++ is flexible enough to do it the java way. For example:
:internal(s) {}
:internal(i) {}
class Object {};
class String : public Object {
public:
String(string s)
operator string() { return internal; }
private:
string internal;
};
class Int : publoc Object{
public:
Int(int i)
operator int() { return internal; }
private:
int internal;
};
stack<Object&> MyStack;
Then you can do it the "Java" way. If you don't feel like typing that code, boost has a library that does the same thing.
The cake is a pie
Look, if you are dealing with a team that has not divided responsibility for design decisions according to a clear system, then that is your real problem, not the lack of compile-time diagnostics. You're also going to get huge numbers of bugs that the compiler *won't* catch.
The problem with C++ in particular is that it is a bondage-and-discipline language. Everyone on your team has to figure out in advance what chains and barriers are going to be put up in order to allow the problem to be solved within the C++ language.
In a dynamic language, you *choose* what barriers to put in place in order to maintain safety. You aren't forced to put a lot of barriers up that will never be needed.
Also, what people miss is that in Lisp, for instance, a run-time error usually puts you in an interactive debug environment, allowing you to make changes to the program (still alive) using the full power of the Lisp language, and the full resources of your program, in order to find the problem, fix it, and continue execution. This is just now coming to pass in the C++ world, with incremental compilation, etc., but Lisp programmers have had this for decades. When you are developing, you will find the errors, and for production, you can write error handlers that catch these various conditions, log them as appropriate, and specify how execution should continue.
The strategies you use with a dynamic language to prevent and deal with these kinds of problems are different than with static languages like C++. The strategies aren't better or worse, just different. What you gain with dynamic languages is a kind of flexibility that allows you to attack the problem, not the language, and to do so with a maximum payoff for programmer effort. What you gain with C++ is the ability to catch certain types of errors, which aren't really that common, especially as intellisense-type tools are becoming much more widespread. Much of the time, when the compiler complains about type mismatches, you add a cast. The language is forcing you to explain yourself again, not really pointing out a logic error in your program.
The real problems that programmers face are errors of logic, which no language can address, and the ability to express the desired operation, which dynamic languages make much easier than static languages, because they don't require as much unnecessary or redundant description.
Well you're basically arguing that functional languages are better than C++ . Which is rubbish, each has its own place.
BTW how often do I use casts in C++? (ignoring dynamic_cast which is an integral part of polymorphism) umm, once a month? If you design well, as you keep going on about, you won't need weird casts all over the place.
LOL, you are right.
... instanceof would allow subclasses, as you showed, and has an according overhead in the VM, while my approach is exact and faster.
:-)
However I'm totaly surprised about the bytecode you show.
It should be:
invokevirtual #12 <Method java.lang.Class getClass()>
getstatic #13 <Field java.lang.Class class$java$lang$Number>
if_acmpne label
And nothing more.
ALSO: you omit some part of the first test, loading x onto the stack and the test/branch as well.
Both test need exact 3 opcodes.
BTW: instanceof and my approach are not the same semantics
Obviously the compiler you used generates over complicated code, sorry, have mine not here but I asume it generates the same code.
So I was wrong regarding "exact same byte code".
And you are still wrong regarding speed
angel'o'sphere
Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
Hey where are templates in Java?
Are you a "working C++ programmer"?