(I have removed waffle, and also added additional justification.) I have deleted what was previously said, and done my best to restate my objections to Templates in CeePlusPlus. I have ''temporarily'' put a copy of everything on the ChrisHandleysDeletions page. If you feel anything previously said is still relevant, please copy it back here ASAP. ---- The problem to which I believe Templates do provide a needed (but overly complex) solution is that of allowing container-like classes to be statically specialized to accept (and return) particular classes. The very simple-to-understand reason for Templates is to implement an algorithm indifferent to a particular datatype. Creating an instance of the template would result in a code like you would get when implementing the algorithm for this particular datatype in mind. The advantage: * Safety: many errors have been introduced by copy&pasting an existing implementation and reediting it for another datatype. * Quick&Save development: say HaarWavelet w... This is what you would get with Java Generics too. The advantage of C++-like Templates are: * Performance for "normal" usage: A template instantiation produces intermediate code which looks like as if you had written the code with the particular datatype from the beginning which is good to optimize. Generics instead use the common root "Object" for all objects like Vector did before. Imagine what this would mean when using basic datatypes like int, float: they first have to be enclosed in a wrapper class (Integer) and if you do this frequently the GC will jam. But even for normal objects this would mean "dereference, dereference, dereference...". * Performance by advantage usage I: C++ templates allow specializations for particular datatypes. This allows one to choose - fully transparent to the user of the class - the best algorithm depending on the datatype. * Performance by advantage usage II: They allow to select an implementation based on e.g. vector lengths. A convolution class for example could use a "spatial" sum-expression algorithm for filter lengths smaller than 8 and an FFT-based convolution otherwise - fully transparent to the user. * Performance by advantage usage III: You can use templates to provide classes to an algorithm. A small example: template > class Filter { public: Filter(T level) : estimator(level) {} void filter(valarray &data); ... private: NoiseEstimator estimator; }; The filter class implements a filter algorithm which depends on a noise estimation. Doing it like in the example above the noise estimation could be implemented in a separate class independent from the filter class. You combine these components via Filter myfilter(10.0); Thus, you can code at a very high abstract level without losing performance since the compiler brings the pieces together. Compile-time linkage is better than dynamic linking at run time since it won't waste CPU power at run time and results in higher optimizable code. Keep this in mind when reading the opinion of my predecessor below. IMHO we're programmers for writing programs for the user and not to satisfy academic arrogance. But I strongly object to the ''other'' uses for Templates, because they can already be solved (dynamically) using standard OOP polymorphism & interfaces. Templates may well provide some (static) efficiency increase, but I do not believe this is justified when a much simpler solutions already exist - FeaturesShouldNotDuplicateOtherFeatures (which naturally goes with AllFeaturesShouldBeSimple). If anyone can provide a (useful but uncontrived) problem which ''cannot'' be easily solved using OOP, that would help justify Templates. ''I don't think any well-rounded sane programmer wants to justify C++ templates compared with their saner equivalents in other languages. But there are many well-known uses for GenericProgramming, CodeGeneration, and HygenicSemanticMacros, which is what C++ templates are trying to be, so many would vote for C++ templates compared with C++ without templates, and so should you. The standard library is now based on templates, you know. But each of those three subjects is a big one, and really should not be addressed on a page about C++ templates.'' ''But a brief note: you asked for examples of "cannot". Well, that's easy enough: anything that needs to be done at compile rather than run time (that's the '''macro''' part), and that includes polymorphism with specialization occurring at compile time rather than run time.'' ''If you, personally, don't think that matters, and that letting all such things happen at run time is fine and dandy, then you don't need such features, and you'd be happy with e.g. Smalltalk. Or, if you're committed to C++, then you should learn to love the at-compile-time offered. :-)'' '''That's pretty much my view; C++ gives to much power (and too many choices) to the programmer in the name of efficiency, and I simply believe this is out-weighed by the complexity & associated problems that most people will have.''' Assuming that the above is true, what should replace Templates? The Java people had come-up with almost exactly the same solution as I imagined - what they call Generics (see http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf). So Java Generics provide the alternative to Templates for statically specializing container-like classes. (Java) Generics fits well into OOP, rather than trying to duplicate statically what can already be done dynamically, and this alone should be enough to commend it - because there is simply no excuse for making something more complex than necessary (AllFeaturesShouldBeSimple). BruceEckel's argument for Templates instead of Java Generics (see http://mindview.net/WebLog/log-0050 & http://mindview.net/WebLog/log-0051 ) is essentially based on the assumption that ''Latent Types are good''. However, I think that LatentTypesSmell, and therefore his argument does not hold water. -- ChrisHandley ---- Templates and GenericProgramming are great, as an abstract idea. The problem with C++ templates in particular is exemplified by the '''common''' occurrence of single error messages that are 100 or more lines long, and essentially indecipherable (which is agreed by multiple C++ compiler implementors/experts to be unfixable, btw). * Unfixable period, or without changing the language spec? ''Unfixable without changing the language spec. The more it is changed (e.g. into that of another language :-) the more fixable the situation would be.'' Part of the problem is that templates have no diagnostic capability whatsoever, and template expansion uses LazyEvaluation everywhere. If one could code compile-time assertions into a template definition, one might be able to write templates that produce reasonable error messages. Also, if templates had true control structures (rather than the useful-but-UgLy hacks based on template specialization documented in GenerativeProgrammingBook), that might help by better expressing the programmer's intent. (And improve performance; one other big problem with C++ templates is the things take ''forever'' to compile). ''I'm not clear that all that would be quite sufficient.'' * Claimed unfixable by whom? As mentioned elsewhere, StlFilt helps a lot. Compile-time assertions are quite possible in C++03 (see BoostLibraries), and the concepts (CppAndConcepts) dropped from CeePlusPlusEleven would have helped even more. Finally, I never understood this aversion to these long error messages. Yes they're annoying, but I find almost all of them are easily decipherable by people with decent knowledge of the templates involved. Everyone who so much as '''uses''' (never mind '''authors''') template facilities in C++, such as STL, will sooner or later (sooner, actually) run into such messages. The reasons for those atrocious messages is multi-fold, and interesting, but add up to a strong indictment of the design of templates in C++. I note that there are other languages, such as CommonLisp, that have strong support for GenericProgramming (including at compile-time when needed), but do not suffer this problem, therefore it is a bug rather than a necessity in that C++ design. ''I would suspect that it is largely down to C++'s insistence on having overloading (in addition to Templates!)'' * You would be incorrect. This is an instance of how a prejudice leads to wild leaps of conclusion. Overloading certainly has its problems in C++ (e.g. they contribute to the StringClassProblem''''''s), but if it were deleted from the language, template problems would be relatively unchanged. * ''Why then do templates lead to indecipherably long error messages? BTW, I am not prejudiced against overloading, I just think they are syntactic sugar, and they seemed a likely cause for long error messages (due to necessary implementation).'' * Because they arise from what amounts to macro expansion of deeply nested names, often long namespace-qualified names, with each templated class/function that you '''tried''' to use having its type "macro-expanded" to include three dozen other private template facilities as part of its implementation...lots of stuff you may never have heard of, and certainly don't want to know about. This sort of thing plagues macros in general, e.g. assembler macros or C macros, but has never, to my knowledge, reached the nightmarish proportions before, that it does in C++. Lisp evades this by treating macros as just regular code that happens to run at "compile time". C++ falls on its face because it macro-expands names and types, and such things '''always''' expand exponentially in complex systems. It comes down to "execute at compile time is good, but expand at compile time is bad." [See above. The LispMacro system is fully capable of including explicit assertions, run at macro expansion time, that allow reasonable diagnostics to be written.] ''What are you trying to say? I believe I was clear about the situation with Lisp. Oh, do you mean that something similar could be done with C++ if the language were changed?'' If the language were changed. (I could think of several other changes which might improve templates as well...) It's kind of odd, since aside from this, STL and Boost and other heavy template users are one of the best things about C++. Talk about a mixed blessing! ''I don't see any reason why STL couldn't be copied in Java, although I only have a cursory understanding of STL.'' * Oh, it could. STL began life in Ada! It has a lot of good design and analysis in it, unlike C++ templates themselves. -- DougMerritt You might check GenerativeProgrammingBook out. ''Why?'' It contains a very good and thorough discussion about the merits and drawbacks of C++ templates, and ways to use them. ---- ''See also GenericsVsSubtyping.'' This link does not seem to have any relevance, since I already implicitly assumed that the level of Generics provided by Java is a VeryGoodThing, and that link simply says that CeePlusPlus Templates & Java Generics are very useful. My contention was that Templates are overly complex compared to Java Generics, for the useful problems that they solve. ''I haven't learned JavaGenerics yet, but they'd be idiots if they didn't learn from C++ mistakes, after all these years, so I certainly would expect it to be better. There's no excuse for it to not be better. Or to put it the other way around, they have the unfair advantage of designing them 15 years later. :-)'' ---- C++ Templates are one of the most powerful features of the language. They provide for compile-time polymorphism rather than the run-time polymorphism seen with interfaces and inheritance. This polymorphism is actually very powerful, because any type that meets the syntactic requirements of a template can be used as a parameter, without having to explicitly declare an interface. This makes it possible to use templates with classes that were designed independently. As well as the GenericProgramming allowed by the compile-time polymorphism of C++ templates, they also allow for code generation and meta-programming, and even some simple reflection - if I can do ''this'', use this algorithm, else use that one. The big downside is the compile time dependencies - since the compiler needs to see the source code for the templates when compiling every bit of code that uses it, this can make compiles take a long time. The error message problem mentioned earlier is less of a problem with newer compilers. In general, I would not say that TemplatesSmell. However, like any powerful feature (such as inheritance), they can be misused. -- AnthonyWilliams ---- For a beautiful application of C++ templates see http://www2.imm.dtu.dk/~km/FADBAD/, I recently used the ideas there to implement a photogrammetry tool that required computing the 2nd derivative of a function computed by a couple of thousand lines of C++ code. I'd love to know how to implement such a thing without templates. ---- Templates provide compile time reflection. See TemplateMetafunctionHasFunction. ---- C++ is one of the most expressive languages I have ever worked with. Problem is, it's got Tourette's Syndrome or something because it often just barks at me and curses. I should hope the design of the C++ language is the problem here and not the features it sports, namely templates. Template specialization and partial specialization are dazzling. Having a template class extend from a virtual base class is lovely magic. If you allow yourself to use macros, well now things can get interesting. I agree, the error messages are ridiculous and difficult to read. The other thing I hate is, once you jump into the templates boat, you start using them everywhere and unless your compiler vendor has worthwhile PrecompiledHeader features, your build times can become dismally slow. In general, my experience with test driven development is hellish in C++ when I use the bells and whistles. I spent 9 months porting Java Fit to C++, (which originally took a weekend for the Java authors to write?). It was a painful experience, but that was more due to the lack of standard unicode and regular expression libraries than it was C++ language issues. I was curious if I could faithfully reproduce the reflection features used in Java Fit using templates and macros. I feel like I succeeded, here are some of the more interesting language features I used: * Macro functions * Macro token pasting operator (##) * Macro "stringifier" operator (#) * Inner classes * static inline operator new/delete (allowed user to supply overrides to me for my heap access functions) * dynamic_cast for upcasting from FIXTURE* to the derived Fixture classes * Creative use of operators: avoid taking local variables to exploit variadicity - I found that if I had a variadic return object from a method on a template class (basically a pointer of a template parameter is the return type for a method) and I fed that to a -> operator connecting me to a named method or field, I could fudge a simple watered down, compile-time reflection mechanism. * Default method arguments * Pure virtual base class to template'd sub-class * Template classes * Template Specialization (partial specialization could not be used since "ol' crusty", VC++ 6.0, didn't support it). * The "caster" operator (led to a lot of ambiguity, so could only use this sparingly.) * Statically constructed objects - allows linker to instantiate classes at system startup (without any heap accesses) - My fixture class factories can link themselves into a global, singly-linked list, and that is where they are searched when needed by the reflection system. * Macro-constructed static methods in inner classes - when writing a class using multiple macros, for example, you can "pass" data or types (using inner template classes) from one macro to another using these static methods in inner classes. * Home-rolled data structures classes like singly linked lists, dynamic arrays, hash tables, etc. * Static linkage - The power of the linker is something to behold, but dynamic linkage forsakes all of that power. I did not want to force users to import any third party libraries or clash with the user's imports since CeeFIT requires static linkage in order to make the reflection facilities work. For the most part I had to roll my own everything. Perhaps the thing I hate the most when reading this features list is the gnawing feeling that I have somehow stolen what I wanted away from C++ rather than it giving it up to me freely. Couple that with some of the tortured hacks needed to get the code to build on VC++ 6.0, Borland C++ Builder 6.0, Solaris CC, and GCC 3.3 (and higher), and I feel like I just pulled off a bank heist. Still, I feel like mine are language design and standard library issues and could be ironed out by language designers without losing expressiveness. If you are interested in checking out what I have done, please visit http://ceefit.woldrich.com or http://fit.c2.com. -- DavidWoldrich As pointed out, C++ templates often produce eye-achingly long error messages, because in the general case the compiler doesn't know which part of the template you may be interested in seeing. However, in ''most'' cases there are several bits you aren't interested in seeing. For example, you want to see: string not basic_string< char, char_traits, allocator > This is easily done by using something like StlFilt to remove the common stuff that you don't want to see because you haven't used any custom allocators, etc. As far as I can see there is no reason why a standard conforming compiler couldn't do this anyway. You would, of course, need a switch to get the full message for the rare occurrences when you do use a custom allocator. ---- CategoryCppTemplates CategoryCpp CategoryCodeSmell