-
Notifications
You must be signed in to change notification settings - Fork 17
/
templates.fqa
419 lines (274 loc) · 43.7 KB
/
templates.fqa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
Templates
{'section': 35, 'faq-page': 'templates.html'}
This page is about C++ templates, one of the largest cannons to aim at your feet that the C++ arsenal has to offer. Templates solve the problems with C macros by creating 2 orders of magnitude more problems.
What's the idea behind templates?
FAQ: A template describes how to build definitions (classes or functions) which are basically the same.
One application is type-safe containers; there are many, many more.
FQA: Let's get a bit more specific. The FAQ's answer is applicable to C macros, Lisp macros, ML functors, functions
like |eval| found in many interpreted languages, OS code that generates assembly instructions used to handle interrupts at run time, and just plain code generation (writing programs that print source code). The purpose of all such devices is meta-programming - writing code that works with code, creating pieces of code which are "basically the same" (after all, they are built from the same rules), and yet have some interesting differences. The question is, how do we specify these rules and these differences?
The approach used in C++ templates is to use integral constants and types to represent the differences, and to use
class & function definitions to represent the rules. The first decision prevents you from generating code
dynamically, because the parameters can only be compile-time entities. The second decision prevents almost
everything else, because you don't get to use a /programming language/ to generate code - the only thing you
can do is write code with some things factored out and made parameters. You can't do as simple and useful
a set of "basically the same" classes as automatically generated class wrappers for remote procedure calls
instead of normal "local" function calls (called "proxies and stubs" in [http://en.wikipedia.org/wiki/Component_Object_Model COM]
terminology; there are many other terms). Even computing the factorial of an integer parameter
is done using so much [35.2 code] abusing the language mechanisms that people with no useful work to do are /proud/ of being able to accomplish this.
Beyond those fundamental limitations, templates follow the tradition of C++ features of interacting poorly
with each other. Templates can't be compiled because they are not code - they are, well, templates from
which code can be generated once you have the parameters, and /then/ you can compile it. C++, like C,
defines [23.10 no way] to locate the compiled code of a definition given its name. Consequently, template
definitions are placed in |#include| files, and /recompiled in each translation unit each time they
are instantiated/, even if the exact same instantiation is used in N other files. This
problem is amplified by the tremendous complexity of the C++ grammar
(the most complicated part of it is probably [35.18 templates themselves]), making this recompilation very
slow. If your code doesn't compile, you get [35.17 cryptic error messages]. If it does compile, you might
wonder what it means. That's where the interactions of the C++ type system
(pointers, arrays, references, constants, literals...), function & operator overload resolution,
function & class template specialization selection, built-in and user-defined implicit conversions,
argument-dependent name look-up, namespaces, inheritance, dynamic binding and /other/ things kick in.
The sheer length of this list should be convincing: neither a human nor a program (say, an IDE) has a
chance against this unprecedented syntactic power.
Poor support for meta-programming is not necessarily a very big deal, because you can do lots and
lots of things without it. That is, unless you work in C++. For example, there are no built-in lists or
dictionaries in C++; the standard library provides templates you can use, so you can recompile the
definition of each kind of dictionary each time you use it in a source file. In fact, most of
the code in the C++ standard library belongs to a conceptually and historically separate library called
STL, which stands for "Standard Template Library". For example, that's where |std::vector|,
which the FAQ recommends to use instead of the [6.15 evil] C arrays, comes from.
If you use C++, chances are that you're going to deal a lot with its obscure meta-programming facilities.
-END
What's the syntax \/ semantics for a "class template"?
FAQ: You add the parameters before the definition of your class, as in |template<typename T> class Array { ... };|,
and then you can use the parameters in the definition of the class, as in |T arr[N];|, and then you can use
your class by substituting the parameters as in |Array<int>|
(the FAQ gives a code listing instead of using words; its example is as simple as that).
FQA: Wow, that sounds easy! Too bad it's wrong, in two ways.
First, things will not follow this straight-forward model - the FAQ itself discusses a couple of cases,
like the [35.18 need] to resort to the |typename| keyword and the [35.19 look-up] of "nondependent names". All such cases illustrate that you /can't/ take the definition of a class, parameterize some things making it a template, and expect it to just work - it's way more tricky.
Second, what about the cases where nobody would /ever/ write the classes generated from templates manually,
but templates are still used because that's the only meta-programming facility offered by C++? Of course
there are also C macros, which have some limitations templates don't have (and vice versa), and at least
compile fast. But in the C++ community, macros are considered the most [6.15 evil] feature ever, and using them is
treated as a sin somewhere between speeding and blasphemy. Anyway, a majority of all uses of templates
[35.1 "beyond type-safe containers"] actually fall in this second category. Let's look at the previously mentioned compile-time factorial example, which is /trivial/ compared to nifty stuff like type lists:
`<br>`
@
template<int N>
struct Factorial
{
enum { value = N*Factorial<N-1>::value };
};
template<>
struct Factorial<0>
{
enum { value = 1 };
};
@
This code generates N+1 classes in order to compute the factorial of N.
Talk about "the syntax \/ semantics of class templates". This is equally disturbing to humans - because it makes so little sense - and to compilers, which internally represent each class using a sizable data structure. This compile time computation technique tends to take a lot of compile time. When your only tool is a hammer template, not only does every problem look like a nail - you also hammer it with 100 hammers.
Oh, and when you want to use a template, be kind with the C++ lexer
(the part of the compiler converting text to "tokens" so that the parser can check whether they make meaningful statements).
Code like |vector<vector<int>>|, which tries to declare an inefficient implementation of a [13.11 2D array],
won't compile - you need a space before the two > characters. Their concatenation looks just like the right bitwise shift operator. This is one of the more harmless, albeit confusing, awkward interactions between C++ features.
-END
What's the syntax \/ semantics for a "function template"?
FAQ: Pretty similar to class templates, plus you can usually omit the template parameters - the compiler will figure them
out from the function arguments. For instance, you can write a |swap| function for swapping two values of any type,
be it integers, strings, sets or file systems (yes, the FAQ /actually mentions/ swapping some |FileSystem| objects).
By the way, an instantiation of a "function template" is called "template function".
FQA: In addition to all the [35.2 problems] with class templates, we are now engaged in a battle of wits with the oh-so-smart compiler figuring out template parameters from function arguments. Or not. For example, |std::max(x,5)| compiles when x is a |int|, but fails to compile when it's a |float| or a |short|. You see, the point of templates is to make "algorithms" work with values of many different types, facilitating "code reuse" (the fact that |x>5?x:5| is less code than |std::max(x,(short)5)| doesn't mean you don't want to /reuse code/, does it?).
For instance, you can reuse |std::swap| to swap a couple of file systems. All you have to do is implement a class
|FileSystem| with a [10.4 default constructor] creating a new empty disk partition. The copy constructor will
copy all the files from a given |FileSystem| to a newly created partition, the [11.1 destructor] will wipe it out,
and |operator=| will do [12.2 the latter followed by the former]. To handle errors, use [17.1 exceptions].
You might get a few extra disk partitions created and destroyed, especially if you pass |FileSystem|
objects around too much in the code, but that's a small price to pay for reusing the 3 lines of code in |std::swap|.
And a "commercial-grade" compiler can even [10.9 eliminate] some of those copies!
The note about "function templates" and "template functions" is very useful. Too bad there are people out there that confuse the two. Be careful with C++ terminology. For example, don't confuse "object files" (compiled code) with "objects" (which belong to a class), which in turn shouldn't be confused with "instantiation" of class templates (substituting template parameters is called "instantiation", the result of this process is also "instantiation", and creating objects is called "construction"). The good (or bad) news is that the terminology is the easy part.
-END
How do I explicitly select which version of a function template should get called?
FAQ: Most of the time you don't need to do it - the compiler will guess. It uses arguments to guess, so when your function has none,
use |f<int>();|. Sometimes you want to force the compiler to choose a different type than it would choose by default -
for example, |g(45)| will instantiate |g<int>|, while you want |g<long>|. You can force the compiler to call |g<long>| with explicit instantiation
as in |g<long>(45);| or type conversion as in |g(45L);|.
FQA: There is a good reason to avoid all kinds of "clever" behavior which gets in your way when you try to figure out
what a program actually does
(it doesn't always do what the author thought it would do). Overloading and template specialization are one kind of this
behavior - go figure which function is actually called.
But let's assume for a moment that it's not a problem, and that the important thing is to write code expressing
the author's intent "clearly" in the sense that it's not cluttered with "low-level" details like which
"version" of a function is called.
In that case, the picture presented by the FAQ looks fair - you only need to explicitly specify parameters when
the compiler has no information to guess them itself, or when you don't like its guess. The truth is more
complicated, because sometimes a function has more than one argument, and the template defines constraints
on these arguments. That's what happens with |std::max(x,5)| when x is a |float|.
The template wants two arguments of /the same/ type, and the compiler thinks that "5" is of type |int|.
So even though the intent seems clear (you probably want 5 to be treated as a number of the same type as that of x),
the compiler can't make a decision.
So you have to interfere in these cases, and choose between two almost equally unreadable alternatives, explicit instantiation or explicit type conversion.
Out of the two options, explicit instantiation, the syntax defined by C++ (as opposed to type conversion which is inherited from C) is typically worse. First, this way the code using a function forces it to be implemented as a template, although it doesn't really care, and makes it harder to get rid of the pesky templates when you feel like it. And second, when the need to interfere and disambiguate arises /inside another template/, you may have to use the following syntax, hideous even by C++ standards:
`<pre>`
a.template f<long>(45);
`</pre>`
While C++ features generally interact poorly with each other, templates set the record by interacting poorly with themselves.
-END
What is a "parameterized type"?
FAQ: A way to say "class templates".
FQA: Hmm, why do we need two ways of saying this?
-END
What is "genericity"?
FAQ: A way to say "class templates". Don't confuse with "generality".
FQA: Hmm, why do we need three ways of saying this? Apparently C++ promoters consider templates an excellent and unique feature, despite their obscurity and the availability of much better meta-programming facilities in many languages. The many different synonyms are probably needed to illuminate the killer feature from many different directions.
-END
My template function does something special when the template type |T| is |int| or |std::string|; how do I write my template so it uses the special code when |T| is one of those specific types?
FAQ: First, make sure it's a good thing to do in your case. Generally, it is when the "observable behavior"
in the special version you want to add is identical to the general case - otherwise, you're not helping your users. If the special case is "consistent" with the generic case, you can do it as in |template<> void foo<int>() { ... }|.
FQA: "Observable behavior" means different things to different people. In particular, many C++ users tend to /observe/ performance (if you don't care about performance, but you still use a language that won't detect run time violations of language rules like out-of-bounds array indexes, you're probably wasting your time).
Consequently, the specialization of |vector<bool>| to be space-efficient (by storing bits instead of bytes) at the cost of speed (individual bits are harder to access than whole bytes) found in some STL versions is not a very good idea, because it ultimately confuses the performance-aware user. If the user wants a vector of bits, the user can implement a vector of bits, or STL could supply one, but it's very inconvenient when you can't have a simple mental model describing what |vector| really means.
In addition, specialization is actually a pretty dangerous trap because it is your responsibility to make sure that all specializations are visible to the compiler
(|#included|) at each point where a template is used. If that's not the case, you can get too kinds of |vector<bool>| instantiated in your program, triggering "undefined behavior" (typically you'll pass a vector of the first kind to a function compiled to work with vectors of the second kind and crash). So specializing /others' templates/ is very likely to lead to a disaster (because you can't make sure that your specializations are visible in code you didn't write),
and libraries which actually /assume/ that you'll specialize templates they define are best avoided.
If you really want to use specialization, take into account that function templates don't support partial specialization ("I want a special version for all types which are vectors of any T"), only class templates do (template functions support /overloading/, which follows different rules). One workaround is to implement a single function template working with any T and delegate the call to a static method of a template class, as in:
`<pre>`
template<class T>
void f(const T& x)
{
FImpl<T>::f(x);
}
`</pre>`
This way, the class |FImpl| can be defined using partial specialization. All these layers of cryptic syntax could be considered tolerable if they ultimately were the only way to accomplish something really useful, and you could forget about them once you were done. But it's actually very easy to program /without/ these complications, and almost always these complications get you nothing except for reducing maintainability, and you get to see them each time you have a compilation error deep down a chain of templates delegating trivial work to each other, and debugging run time errors becomes a real nightmare.
Basically you can choose simple interfaces and simple implementations, or C++-style cryptic interfaces and cryptic implementations. It's a trade-off.
-END
Huh? Can you provide an example of template specialization that doesn't use |foo| and |bar|?
FAQ: For instance, you can "stringify" values of different types using a template. The generic version boils down to |ostringstream out; out << x|. But you might want to define specializations to handle types where the |ostream| output operator doesn't do what you like (you can set the output precision of floating point numbers, etc.)
FQA: This means that all values of the same type will have to be formatted [15.8 identically].
For example, all integers will be printed using decimal digits. If you prefer hexadecimal, you can define |class HexInt|
(a template, of course, so that it can handle all the different integral types, including user-defined ones). Then you can use |stringify(HexInt<int>(x))|. You might need a partial specialization of |stringify| for |HexInt<T>| (see [35.7 previous FAQ]). To save the trouble of explicitly passing the template parameters to |HexInt|, use a creator function template |HexInt<T> hexint(const T&)| - the compiler will figure T out from |stringify(hexint(x))|.
Specifying a number of leading zeros (as in the format string |"%08x"|) using advanced C++ type-based techniques is left as an exercise to the reader.
We've done quite some work indeed in order to print an integer. Time to relax and let the compiler concentrate while it cleverly figures out all the things we want it to figure out. You usually print stuff for debugging, so the long build time may be annoying, but it's sure better than using a visual debugger where you get to see the line noise generated from all those other templates.
In the meanwhile, it is quite likely that whatever your /real/ job was, someone else (probably some kind of competitor) has already done it. But did the result contain a mature, generic and efficient printing infrastructure with really, really minor usability and maintainability problems? Most certainly it didn't. Which is why C++ template specialization is your friend.
-END
But most of the code in my template function is the same; is there some way to get the benefits of template specialization without duplicating all that source code?
FAQ: You can factor out the common code and only specialize a helper function called from the common code. Two screens of source code are attached for illustration.
FQA: Factoring out common code and helper functions are indeed very useful (which is why you can do that kind of thing with virtually every programming language). The existence of this question in the FAQ seems to indicate that people get unbelievably confused by templates, and lose hope that anything useful they know is applicable to them. Which is not that much of an exaggeration.
-END
All those templates and template specializations must slow down my program, right?
FAQ: You guessed wrong. Maybe the compilation will become "slightly" slower. But the compiler ends up figuring out the types of everything, and then doing all the usual nifty C++ optimizations.
FQA: You guessed right. And the compilation will become intolerably slow. It's not like the FAQ is lying - it's just talking about the state of affairs in [6.1 theory],
where C++ belongs. The "slight" slowdown of compilation is not even worth discussing: everything is
"slight" if you have lots of time on your hands. Just try to build a C program and a /modern/ C++ program full of templates
and compare the time it took. As to execution time, there are practical problems making programs generated from templates slow compared to the hand-written alternatives.
First, the compiler generates the same code over and over again. Sometimes the linker throws away the extra copies and sometimes it doesn't, and the size of your program increases. In particular, the linker doesn't have a chance to throw away the functions which are identical at the /assembly/ level, but not at the /source code/ level (think about |vector<int>| and |vector<void*>|). It is possible to implement templates in a way avoiding these problems (by using the same implementation for all specializations yielding the same assembly code). It is very tedious and almost never done. Two identical functions almost always take more time to execute than a single function called twice, which has to do with instruction caches - a useful gadget frequently overlooked by many [10.9 people] who care about "theoretical efficiency" without actually /measuring/ performance.
Second, when people work with templates, they use /types/ - their only hammer - for saying almost everything (consider the |HexInt| class from [35.9 the previous FAQ]). More specifically, they wrap simple values of
built-in types in user-defined types - classes. The type is used to select the right specialization and what-not -
in fact it's used to specify what to do. An extreme example is the [http://www.boost.org/doc/html/lambda.html boost lambda library] - it creates structures representing entire /functions/, with a sub-structure representing addition, a sub-structure representing the constant 1, etc.
Now, "theoretical performance fans" may think that all of these structures get optimized out by the clever compiler. In practice, that's almost always close to impossible to do because of the so-called [18.14 pointer aliasing problem]. When you have a local variable x, it's clear that nobody can change it but the code of the function, so the compiler can do lots of things with x, like stuffing it into a register or even completely optimizing it out. But once you push x into a structure, it's hard to see where it's modified - go figure who has a pointer to that structure, especially if you pass the object to a separately compiled function. So the compiler has to allocate a memory slot for x and make sure the memory cell gets updated when x is modified and that the memory cell gets read when there's a chance that it could have been changed by someone else. Code working with templates and relying on types to do compile time dispatching ends up doing lots of memory load\/store operations at /run time/ since the types don't really go away.
And anyway, there's such a huge amount of scenarios to take care of to optimize complicated template-based code well that compiler writers rarely bother. They are lucky if they get the /parsing/ right. Even that is unlikely - when you are porting from one compiler to another, chances are that most of your compatibility problems will come from the semantics of the code using templates.
-END
So templates are overloading, right?
FAQ: They are in the sense that they are inspected when the compiler resolves names (figures out the version of |f| that should be called by |f(x)|). They are not in the sense that the rules are different. Specifically, there's the SFINAE (Substitution Failure Is Not An Error) rule: the argument types have to match exactly for a template to be considered in overload resolution. If they don't, the compiler won't try to apply conversions the way it would with a function - instead it will discard the template.
FQA: Aside from the fact that the acronym "SFINAE" interpreted literally doesn't seem to describe what it's supposed to describe, this sounds /just a little bit/ too easy. For example, what does "exact match" mean? Let's have a look at a real life example taken from the GNU implementation of the C++ standard library. I tried to make this short, but there are about `<b>`5`</b>` distinct stupid things involved, so it was hard. If you get tired in the middle of this and stop, it's probably an indication that you /do/ get the main point - that things are actually very complicated in this department and that these complications are best avoided.
`<b>`Stupid thing #1`</b>`: Once upon a time, |vector<int>::iterator| was a plain old |typedef| for |int*| in the GNU STL. Of course this is /very, very/ dangerous: people might use |std::vector| as if it were just an array of objects - a serious abstraction violation, you could get arrested for that in some jurisdictions. At the beginning of the 21st century, the guys behind GNU STL decided to "fix" this by creating a class template called |__normal_iterator|. This template serves as a "strict typedef" - it wraps any existing iterator type, such as |int*|, and delegates all operations to the existing type, but can not be converted to |int*|. This has many important benefits over the previous implementation, for example, much longer [35.17 error messages].
`<b>`Stupid thing #2`</b>`: As you may know, there are two kinds of iterators defined by STL containers: |iterator| and |const_iterator| because of [18.2 inherent problems with const]: |const iterator| is /not at all/ the same as |const_iterator|. If STL wanted to be consistent, it would also define |volatile_iterator| and |const_volatile_iterator|, and then nobody would even look at STL, which wouldn't necessarily be bad. But they didn't. So now you also need two kinds of "normal iterators" - for |int*| and |const int*|.
`<b>`Stupid thing #3`</b>`: /Of course/ the GNU STL guys didn't want to define a |__normal_const_iterator| - after all, making conversion hard for /you/ is an excellent thing, but making it hard for /them/ is a completely different thing. Instead, they decided to support automatic conversion between different instantiations of |__normal_iterator|, by - of course - delegating the conversion to the wrapped types (templates normally delegate all useful work to someone else; their job is obfuscation). This way, you can compare const and non-const iterators using the same operator, having this elegant prototype:
`<pre>`
template<typename _IteratorL, typename _IteratorR, typename _Container>
inline bool
operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
const __normal_iterator<_IteratorR, _Container>& __rhs);
`</pre>`
`<b>`Stupid thing #4`</b>`: STL provides another, /seemingly unrelated/ service to its users. It defines global relational operators which work on arguments of any type. How can they compare objects without knowing anything about them? At this point you can probably guess the answer - of course, they delegate the work to someone else, this time to /existing/ relational operators, using interesting identities such as |(a>b) == !(a<=b)|. This way, you can define only 2 relational operators, and get the rest "for free".
`<b>`Stupid thing #5`</b>`: Except when you can't. This is where our subject, overload resolution and templates, kicks in. Remember the rule about only considering templates when the argument types match the prototype /exactly/? Well, when you compare "normal iterators" of the same type (for example, both wrapping |int*|), the beautiful prototype above matches the arguments "exactly". So do the "generic" relational operators. Oops, we have ambiguous overloading! The "solution" is to define a /third/ overload, matching the types /even more exactly/ by using a single template parameter |_Iterator| instead of two which can possibly differ. Why is this situation considered "unambiguous"? Frankly, beyond the basic intuition saying that you must show the compiler a type pattern as similar to your arguments as possible, I don't know. That's why I didn't list the Stupid thing #6. But the first 5 make me feel that in this case, /ignorance is bliss/.
Apparently this situation looks discouraging even from inside the C++ universe, as indicated by the following /rather sad/ comment found in one of the header files of the GNU STL. You can probably decipher it, unless the 5 stupid things above have already faded from your memory:
`<pre>`
\/\/ Note: In what follows, the left- and right-hand-side iterators are
\/\/ allowed to vary in types (conceptually in cv-qualification) so that
\/\/ comparison between cv-qualified and non-cv-qualified iterators be
\/\/ valid. However, the greedy and unfriendly operators in std::rel_ops
\/\/ will make overload resolution ambiguous (when in scope) if we don't
\/\/ provide overloads whose operands are of the same type. Can someone
\/\/ remind me what generic programming is about? -- Gaby
`</pre>`
This could be amusing (an implementor of the standard library of a language complaining about this language in files delivered to users and all) if it weren't so mind-numbing. People who think they are better at C++ than the GNU STL authors are welcome to waste their entire life chasing and "solving" problems with overload resolution, template specialization or whatever its name is. For the rest, trying to avoid templates & overloading sounds like a good advice, which can be followed to an extent even if you are forced to use C++.
-END
Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?
FAQ: "Accept these facts", says the FAQ - templates are not code, just a recipe for generating code given parameters; in order to compile this code, it must first be generated, which takes knowing both the template definition and the definitions of the parameters which are passed to it; and the compiler doesn't know anything about code outside of a file when compiling the file (which is called "separate compilation").
So you have to place template definitions in header files, or else the compiler won't get a chance to see all the definitions it needs at the same time. Experts should calm down - yes, it's oversimplified; if you know it is, you don't need this answer anyway.
FQA: There are two problems with placing template definitions in header files which may bother you: you get to recompile them each time the file is included, and you disclose your source code to the user. Let's concentrate on the first problem. The second is minor anyway because source code of templates isn't necessarily easier to understand than disassembled object code. As to the first problem - to get an idea about its magnitude, consider the fact that an iostream-based "hello, world" program requires the GNU C++ compiler to parse `<b>`718K`</b>` (!!) bytes. And contrary to the claims in the FAQ, it turns out that the need to make the source code of templates available to the compiler is not the only reason we have this problem.
Suppose a C++ compiler could use some rules to locate compiled definitions of classes given their names, for example "|std::vector<int>| is always located at the file |$OUTPUT_ROOT\/templates\/std\/vector_int.o|" and so on. This way, if you used |vector<int>| and |vector<double>|, you'd have to compile |vector| twice, but if you used |vector<int>| twice, the compiler could avoid recompilation. That would make sense since you'd only compile /different/ classes each time you compile the template.
Unfortunately, this can't work in C++. That's because the compiler can't /parse/ |std::vector<int>| without parsing
the entire preprocessed output generated by |#include <vector>|. That parsing, which /has/ to be done over and
over again for each compiled source file, takes most of the compilation time. Generating the code of |std::vector<int>|
several times is the small part of the problem, and most compiler writers don't bother to solve it, since you'd still
have the parsing bottleneck.
The basic problem inherited from C is that the compiler can't look up
definitions. Instead, you have to arrange |#include| files so that the preprocessor can copy-and-paste definitions into a single huge bulk containing everything relevant (as well as many irrelevant things) for the compilation of your source file. C still compiles fast because its grammar is simple. Many newer languages define not only the concept of a "class", but also rules to help the compiler locate definitions instead of parsing them over and over again. C++ programmers enjoy the worst of both worlds.
-END
How can I avoid linker errors with my template functions?
FAQ: You probably didn't make the definition of a template available to your compiler at the point where a template is used (did you implement a template in a .cpp file?). There are three solutions:
`<ul>`
`<li>`Move the definition to the .h file (which may increase the size of your compiled code, unless the compiler is "smart enough").`</li>`
`<li>`Add explicit instantiations in your .cpp file. For example, |template void foo<int>();| will cause the compiler to generate the code of |foo<int>|, and the linker will find it.`</li>`
`<li>`|#include| the .cpp file defining the template at the .cpp file using the template. If it feels weird, live with it or read [35.12 the previous FAQ].`</li>`
`</ul>`
FQA: These "solutions" create new problems:
`<ul>`
`<li>``<b>`Moving code to .h file`</b>`: even if the code size doesn't increase, the compilation time will - you are going to recompile your templates from scratch each time they are used, and templates are one of the hardest parts of C++ to compile. It's nice that the FAQ at least acknowledges that your code size /might/ increase though - in practice it most certainly /will/. Too bad the FAQ didn't mention it in [35.10 the question about the speed of templates] - replicated code means more time spent in fetching code into instruction caches.`</li>`
`<li>``<b>`Explicit instantiations`</b>`: this is one big step back to C macros. Suppose you have a parameterized preprocessor macro which expands to a definition of a container class. One difference between this macro and an equivalent template is that if someone /uses/ one such class, that someone must also make sure that the macro is actually /expanded/ somewhere with the appropriate parameters - or you must provide these expansions. Otherwise, there will be linker errors. With templates, the compiler is supposed to generate the needed instantiations transparently - except it's almost impossible to accomplish. Along comes this "solution", moving us back to square one.`</li>`
`<li>``<b>`Including the definition at the point of usage`</b>`: this shares the problems of the first two options. If you use templates in .h files, you may have to include the .cpp files defining them in these .h files, getting the problems of option 1. But the benefit of option 1 - transparency - is gone: quite similarly to option 2, it is now your job to make the definition of a template available wherever the template is used.`</li>`
`</ul>`
-END
How does the C++ keyword |export| help with template linker errors?
FAQ: It's "designed" to eliminate the need to make the definition of a template available to the compiler at the point of usage. Currently, there's only one compiler supporting it. The keyword's future is "unknown".
An advice for futuristic programmers follows. It shows a way to make code compatible with both compilers that support |export| and those that don't using - guess what? - the wonders of the [6.15 evil] C preprocessor. Among other things, the FAQ advises to |#define export| under certain conditions.
FQA: "How does it help", is that what you want to know? OK then. The |export| keyword helps with template linker errors just the way a song about peace helps to stop a bullet penetrating a foot. It helps just like a keyword |findbugs| telling the compiler to find and report all the bugs in a piece of code would help you with bugs.
The rest of C++ makes this keyword impossible to support in any useful way that would actually yield faster compilation compared to the case when template definitions are included at header files. That's why most compilers don't bother to support it, and that's why the future of the keyword is "unknown": it's useless.
If you spot someone following the FAQ's advice (|#ifdef EXTRATERRESTRIAL_COMPILER| and all that), call an ambulance. Warning: the patient has likely reached a very agitated state and might escape before the people qualified to deal with the situation arrive. Try to occupy the patient's mind with a discussion about the fact that |#defining| keywords is illegal C++. Propose to consult your lawyer. Try to "design" a couple of keywords together (look up synonyms in a dictionary, imagine them printed in popular fonts, stuff like that). Improvise. It's gonna be over soon.
-END
How can I avoid linker errors with my template classes?
FAQ: It's just like errors with template functions, which were explained in the previous answers.
FQA: Yep, it's about the same.
-END
Why do I get linker errors when I use template friends?
FAQ: If you have a class template |C| declaring a friend like |Foo<T> f()|, the compiler assumes that there's a global function |f()| returning |Foo<T>|. You probably meant a different thing, namely - there's a function template |template<class T> Foo<T> f()|, and you want its instantiation |f<T>()| to be a friend of your instantiation |C<T>|.
There are two ways around this:
`<ul>`
`<li>`Declare the function template before the definition of the class, and add |<>| to the friend declaration, as in |friend Foo<T> f<>();|`</li>`
`<li>`Define the friend function template inside the body of the class.`</li>`
`</ul>`
FQA: In both solutions the syntax is unrelated to the semantics to an extent remarkable even for C++.
Why does |<>| mean that we are talking about an instantiation of a template function? Why not use a keyword (like, just an example off the top of the head, the |template| keyword) to say that?! The C++ way is uncompromisingly ugly, especially in the example mentioned by the FAQ itself: |operator<< <>(...)|.
And even when you don't have a problem with placing the definition in a header file, the seemingly cleaner second way is actually /more/ cryptic. This breaks one of the /very few/ things in C++ you can normally count on: that a declaration of a function or a type looks just like a definition without the body. Here, we change the meaning of the prototype by adding a body: instead of declaring a function, we now declared and defined a function template.
Last but not least, the very fact that this problem /exists/ is an indication of a readability problem with the C++ grammar. How many people would guess that the original declaration refers to a function and not a function template?
How is one supposed to navigate through this swamp of arbitrary syntax? /Of course/ one shouldn't expect the kind of readability you get with a natural language from a programming language. /Of course/ any formal language will behave "counter-intuitively" at times. But people /do/ deal with formal languages quite successfully, when it is possible to keep a reasonably compact model of the key rules in one's mind. In these cases, even if you bump into a behavior which doesn't make sense at the first glance, you can think again and - "Of course, of course, I know what it's doing!". Do you feel that you understand what a C++ compiler is actually doing? Neither do most C++ users out there.
-END
How can any human hope to understand these overly verbose template-based error messages?
FAQ: There's a "free tool" converting compiler error messages to more human-readable ones. It works with many compilers.
An example follows, having a snippet |[STL Decryptor: Suppressed 1 more STL standard header message]| in it.
FQA: Oh /really/? /Any/ "template-based" error messages? Hmm, why didn't the compiler writers produce clean error messages in the first place if a single tool can clean up all the mess created by many different compilers? These people must be quite lazy and\/or stupid. Or are they?
Actually, no, they are not. The error messages are cryptic because templates are cryptic, and most compilers can't really do much better than they do today.
The tool mentioned (/without the name/) and [http://www.bdsoft.com/tools/stlfilt.html linked to] by the FAQ is called |STLFilt|. That's why the FAQ doesn't mention the name. That's why its output does mention STL. That's why it works at all - you can't improve generic template error messages, but you can filter STL-related messages if you know how STL is implemented in each specific case.
We need a couple more tools, like |STLCompilationTimeReducer| and |STLDebugInformationBeautifier|, and we're all set. Yet another proof that generic meta-programming facilities are a [6.2 better] way to implement containers than build them into a language.
If you wish to implement a template library, don't forget to implement a tool filtering the error messages your users will get, as well as the other cool tools, for all the flavors of compilers out there.
-END
Why am I getting errors when my template-derived-class uses a nested type it inherits from its template-base-class?
FAQ: This can hurt, sit down. The compiler doesn't look for "non-dependent" names (ones that don't mention the template parameters) in "dependent" base classes. So if you inherited a nested class or typedef |A| from your base class |B<T>|, you can only access it using a dependent name, like |B<T>::A|, but you can't use a non-dependent name, like plain |A|.
/And/ you'll have to prefix that "dependent" name with the |typename| keyword. That's because the compiler doesn't know that |B<T>::A| is a type (think about two specializations, one defining a nested class |A| and one defining a global variable |A|).
FQA: This illustrates two generic problems with the C++ grammar.
First, class templates are /not/ [35.2 just parameterized class definitions], because the crazy C++ name look-up gets crazier when you are inside a template. So don't assume you can take a C++ class definition, factor out a bunch of parameters and get a working template definition.
Second, telling a C++ type name from a C++ object\/function name is [10.19 insanely complicated]. This interacts badly with templates, constructors, and everything else.
As to the possible reactions of users the FAQ attempts to anticipate: while /running away/ may be justified, /sitting down/ is probably not. Good developers tend to /test their code/, so even if the compiler didn't spit an error message and did the wrong thing silently (for instance, used a type called |A| from the global namespace), a test will find the error. Stupid compiler behavior only feels like pain for people who think that the extremely slow C++ compilers spend their time in finding all their bugs, and don't bother to test the result. Those people should relax and save their tears for the C++ /run-time/ errors.
-END
Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?
FAQ: The reasons are identical to those in [35.18 the previous FAQ]. But the workarounds are /different/ - convert |f()| to |this->f()| or add the statement |using B<T>::f()| to your class definition. Using the fully qualified name like it was done in the previous FAQ (|B<T>::f()|) will also work, except when the function is virtual, in which case the compiler will use static binding, not dynamic binding.
FQA: Yep, the case with member functions is similar to the case with nested types, with the additional bonus of interacting badly with [20.1 virtual functions].
The FAQ has a hilarious comment in the spirit of "this doesn't mean that template inheritance doesn't work - but the name look-up works differently". And that's C++ for you: it's not like you can't write code, it's just that you can't tell for sure what any particular name or some other part of it means.
-END
Can the previous problem hurt me silently? Is it possible that the compiler will silently generate the wrong code?
FAQ: Yes - the compiler might call a function or use a type from the global namespace instead of what you meant, for example.
FQA: It's not as horrible that a language can silently misinterpret what you mean as it may sound. Any language will do this to the creative but imprecise human mind (formal languages aside, people frequently misunderstand each other).
With formal languages, you can form a relatively simple model which will help you understand these problems. It's the same with C++ except for the "simple" part, so C++ and you will misunderstand each other pretty frequently.
And you can also test your code by creating programs that check if it does what you want it to do in a bunch of cases. It's the same with C++ except that it compiles forever and you have to write notable amounts of code to implement the simplest test, so C++ code ends up being tested pretty rarely.
-END