10 ms·
An Idiot's Guide to C++ Templates - Part 1
- madsravn 14y agoFor an old language as C++, templates have a way of staying new, exciting and hard at times. I have respect for people who can explain the deep intricacies of the vastness of C++. Good article.
- brudgers 14y ago"It is also true that code size would increase, since there are now two function definitions... ...But, on a positive side, when you manually define N different overloads (say N=10), those N different overloads would be anyway be compiled,linked and packed in binary (the executable). However, with templates, only the required instantiations of function would get into final executable. With templates, the overloaded copies of function might be less than N, and it can be more than N - but exactly the number of required copies - no more no less!" There are times when every byte counts. Most of them were before the second Clinton administration. Odds are that with RAM at $20 a Gig, a few dozen bytes isn't the difference between your program being memory constrained or well tuned. Contemporary memory issues tend to be orders of magnitude larger.
- btilly 14y agoThere are times when every byte counts. Most of them were before the second Clinton administration. The CPU caches on a modern computer disagree with your snark. As http://everythingisdata.wordpress.com/2009/10/17/numbers-everyone-should-know/ http://everythingisdata.wordpress.com/2009/10/17/numbers-eve... shows, there is a huge performance benefit when you can stay inside of cache. (Note, those numbers are from Jeff Dean, who is widely lauded within Google for building the infrastructure that makes Google possible.) Therefore when you're squeezing performance, precise control of memory layout matters a lot. That said, most of us don't need to worry about it. But when you do need to worry about it, there is absolutely no way to get it if you've already given up control. I am averaging needing to worry about it about once every 5 years. So I need to care for perhaps 3% of my coding time. That percentage varies greatly by developer. Most developers that I know don't have the necessary skills to consider tackling issues at that level and so by definition can never take on projects for which they would care. Some developers work on stuff for which they need to care all of the time. But even if you don't personally need that, it still is good to recognize that there are some who really do.
- brudgers 14y agoThe Neil Conway blog begins: When you’re designing a performance-sensitive computer system... Neil then suggests two tools for achieving such designs, intuition based back of envelop calculations and microbenchmarking to identify bottlenecks. Good intuition is the result of completing Norvig's ten year course. Identifying performance bottlenecks requires running code. Neither is relevant during the "Template administration." Back of envelop calculations are about determining architecture, not the specific lines of text to be compiled. It's a look at efficient gross resource consumption, not tweeking handfuls of bytes. Tweeking, when it must occur - per your experience more than an order of magnitude less frequently than non-performance sensitive applications - is well after the "Template adminstration". My criticism is literary. The article throws in byte sized boogie men. These are the sort of things that Google pays gurus to deal with. Not the sort of work for which they hire C++ programmers who need an idiot's guide to templates. To a first approximation, memory isn't precious any more. Even when programming in C++. Writing as if it is, develops bad intuitions of the sort that lead to concern over templates during the Design phase. I suspect that your first line of defense against running out of memory was not looking template construction, but compiler optimizations. Managing memory manually in C++ is hard enough without creating a mindset which encourages premature optimization.
- btilly 14y agoMy personal anecdote disagrees with you. I do not make the decision to write performance critical code in C++ until I have an analysis of the problem which includes a prototype in a slower language. Therefore I do not start writing C++ templates until after I already have a specific problem, and a pretty detailed layout of how I want my data to be laid out in memory. The details of how my code gets laid out in memory I gladly leave to the compiler. But it is important for me to know that I can use templates and I won't have to worry about it either. I suspect that your first line of defense against running out of memory was not looking template construction, but compiler optimizations. Managing memory manually in C++ is hard enough without creating a mindset which encourages premature optimization. Not true! In the latest project that this came up in, one of the first templates that I wrote in C++ allows me to replace things that can go into a std::map with 4-byte objects that are simply indexes into a deduped vector. (This is on Linux, so I don't have to worry about dword alignment. Thus 4-byte objects only take 4 bytes.) Given that I have a very large number of these, often need to compare two to know if they are the same or different, and only seldom need to get at the actual value, this gives huge memory and performance benefits. Of course doing this kind of thing for a general-purpose application would be horribly premature optimization. Which is why I only considered going to C++ after analyzing where the issues were in my first two Perl versions. And I am an example showing that it isn't just C++ gurus who find themselves needing to write performance critical code in C++. In fact my desire to avoid premature optimization means that when I do need to write performance critical code in C++, I do not know the language very well because I use it so seldom!
- mpyne 14y agoAnd even when every byte does count, it's usually possible to make only a single real template expansion for an opaque handle type like pointer-to-void. This breaks type safety and has other issues but generally works well.
- btilly 14y agoIn my (deliberately) limited C++ experience, I'm basically able to dream up how a program would work in a scripting language, translate all of the datatypes that I'm used to like growable arrays to STL equivalents (std::vector< ... > and std::map< ... > cover most of my use cases), and then after much verbosity and debugging, I get a magically fast program. However the biggest frustration for me (aside from the verbosity) is that things work until they suddenly don't work, and then it isn't obvious why they don't work from the debugging stack you get back. They often don't work for good reason - but unless you're a C++ expert you don't know that reason. For example suppose that I have a class that has reference members. Those are fields specified with & - they are kind of like a pointer except that you can't change them, and you use . instead of ->. Because you can't change them, operator= is not generated for you. I didn't notice this until I tried to use one in an std::map< ... > and everything blew up. However luckily confusing backtrace message plus google usually leads to a useful stack overflow answer, else I'd find this process much more painful. My one remaining frustration is that I hate how the STL did iterators. In the STL, if you have a data_type< foo > template, you iterate over it with a data_type< foo >::iterator. So you get a std::vector< foo >::iterator, a std::set< foo >::iterator, a std::dequeue< foo >::iterator, etc. This is great for the compiler, but as a programmer it is backwards. I don't care what kind of data structure this came from, I care what kind of data type I get out. I'd like to see those three examples produce an iterator< foo >. And then you can dream up things like the ability to take an iterator< foo > and a method on foo that will return a bar, to get an iterator< bar >. I am used to having map/grep/etc, and it would be nice to be able to translate list-oriented thinking into C++ with less verbose boilerplate.
- jevinskie 14y agoThe iterator typing is much improved in C++11. It's just auto adt.begin().
- btilly 14y agoThere is less verbose repeating of verbosity. But the types did not change in anything like the way that I would like. Try to translate http://perl.plover.com/Stream/stream.html http://perl.plover.com/Stream/stream.html into C++ iterators to see how the current abstraction limits the ways you can think about a program. By contrast suppose that my hypothetical iterator< foo > type was required to have a pointer overload, and supported the methods done() and next(). Now go back and try to translate that article - you'll find that it is pretty easy.
- 16s 14y agoI like templates for code reduction. By using a template, I turned about 12 functions into 1 function once. Makes code maintainability much easier.
- pandaman 14y agoI might have been just lucky but I have not yet seen a C++ programmer who passes a job interview yet is unable to comprehend the simple template syntax. The opposition to templates that I have seen is not based on the ignorance of the basic template concepts. Quite the opposite - it's based on the partial knowledge of the advanced templates. Usually such people are cool with STL or STL-like home-brew collections but when they hear "metaprogramming" they immediately start having kittens :) Essentially (class) templates are meta-functions over C++ types and templates themselves and the article describes only their basic application i.e. linear functions, over concrete types only and without any control structures. It's almost exactly as same as explaining Haskell without recursion and pattern matching.
- ysapir 14y agoThe article does not describe the primary issue with using templates: that using templates leads to hard-to-manage non-modular code. Templates have their uses, but a big problem is that any change in template code means recompile of any code that uses it. Additionally, the interface contract is not well defined. Adopting an interface/inheritance approach generally leads to much more maintainable code. And yes, you can use namespaces and careful template programming to give some modularity to the code, but in the end, if one code line change in one template header, that is used by multiple other template headers, and in turn by multiple libraries, means you have to recompile thousands of files and dozens of libraries, this is a very big price to pay. The article starts with function templates, which are tricky, with function overrides interfering with template instantiations. The article seems oblivious to this issue. "void PrintTwice(const TYPE& data)" If you are going to make a function template that ought to work with primitive types accepts a primitive type, const& may not be that simple. You may want to write a separate template implementation (and choose between them using enable_if<> and type_traits), because you don't want to take a pointer/reference to an int if you don't have to. "You should have noticed that I used typename, instead of class. No, it is not required to use typename keyword if a function returning something. For template programming, these two keywords are very much the same." I have generally used <class X> rather than <typename X>, following a comment by David Abrahams to that effect on the boost list a long time ago. I think it has to do with the fact that typename does have multiple meanings inside the angle brackets. "int tSum = int();" I think this code is problematic.