____ _ / ___| _ _ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ | | _| |_ _| |_ | | / _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ | |__|_ _|_ _| | |__| (_| | | | | (_| | |_| | (_| | (_| | __/ \____||_| |_| |_____\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| |___/ |___/ This reference covers only those things that I find I regularly need to look up. Things which are so straightforward that I could not possibly forget them even after a decade of disuse are not mentioned. LVALUES AND RVALUES ~~~~~~~~~~~~~~~~~~~ An lvalue is something that has a memory location. An rvalue is anything that is not an lvalue. Once upon a time in pre-const C, lvalues could be on the left-hand side of assignments. rvalues come from: address-of function returns which are not references All operators EXCEPT [], dereference, assignment A cast to anything that is not a reference type Built in address-of, ++, and -- operators require lvalues, but this is not necessarily true for user overloaded versions. TYPEID ~~~~~~ #include // You cannot actually declare variables of type std::type_info - the // constructor is private. You must save things to references. const std::type_info& t = typeid(object-or-expression); t.name(); // returns const char * // Other than printing the name, comparing to others is all you can do. // You can decode the name with c++filt; try -t option OPERATOR OVERLOADING ~~~~~~~~~~~~~~~~~~~~ Almost all operators can be overloaded, so it is easier to list those which cannot: :: . .* ?: sizeof() typeid() FUNCTIONS AND CLASSES ~~~~~~~~~~~~~~~~~~~~~ The following public functions will be created for you: default constructor (if *no* user constructors are defined) copy constructor copy assignment operator (if possible - no references, const members or base classes with private operator= ) destructor (default is not virtual) Note that the default behavior of these copy methods, a memberwise copy, is very often wrong. It is considered good practice to inhibit them by default (by making them private and not defining them), and allow them only in special cases. (Stroustrup 246, Meyers #5,6) Similarly, make the destructor virtual if there are any other virtual functions. Function Modifiers: Constructors can be declared "explicit", which will prevent them being used in assignment operations where they are likely wrong (Stroustrup 284). Member functions can be const, which means they do not modify the underlying object (Stroustrup 228). Const functions have a separate signature from non-const, and in fact it is often useful to define both. However, individual members may be declared "mutable", and this means that even const functions can modify them; they are intended to be used for caches or precomputations which do not change results. Construction: Note that the syntax of calling a default constructor is different from that of a non-default constructor. Here's a constructor which takes arguments: Foo f(1,2,3); but if we want one which takes no arguments, there are no parenthesis: Foo g; If we used parenthesis, we'd be defining a function with return type Foo. This becomes significant again when combined with the idea that template specializations allow out-of-class declaration of members. Stroustrup 244 has a long list of ways that objects can be created and destroyed. Builtin types get no default value, so for a template to ensure they are initialized, a constructor must be invoked in the initializer list with empty parameters. Overload resolution steps: 1. Exact match or lvalue transformations (array->ptr, add const, lvalue to rvalue, function to function pointer) 2. Match using promotions: bool->int, char->int, short->int, float->double, double->long double 3. Match using standard conversions 4. Match using user-defined conversion sequence (a sequence has: optional standard conversion, single user-defined conversion, optional standard conversion) 5. Match ellipsis Within a category, if one possibility is a subsequence of another, that one is better. If two sequences differ only by qualification adjustments, the one with fewer adjustments is better. It is a compile-time error if there are two possibilities, neither of which can be judged better than the other. See See Stroustrup 7.4 and C++N p123. With overloaded operators, if a member and non-member both match, the member is preferred. Note that it is generally undesirable to define binary operators as members, because the left hand argument will then not have conversions like the right. Overloading does not occur across non-namespace scopes, such as at the root level and within a class, or between a class and the inherited class. If you override a fucntion in an inherited class, that hides *all* the versions from the base class. The standard technique for avoiding this is a using declaration. Inheritance: If a base class is declared "virtual" it means that only one copy will be instantiated altogether instead of one per path to it. This matters only in the case of multiple inheritance. If you declare a function virtual in a class which is not the first class in the heirarchy to have the function, you'll get what you asked for (virtual through pointers to that class, but not to its base). Typedefs in derived classes replace those in base classes. Covariant return types of overridden functions are allowed. Address of Overloaded Functions: A cast is necessary to disambiguate. For example: void func(int) { printf("func int\n"); } void func(long) { printf("func long\n"); } ... printf("%p\n", (void (*)(long))func); A similar issue can arise when passing a function as a template parameter. Member Function Pointers: Declaring: retval (Class::* fp)(func_args); Assigning: fp = &Class::function; using: Class c, *cp; (c.*fp)(args); // Parenthesis NOT optional (cp->*fp)(args); Member functions do not decay into pointers the way normal functions do. It is NOT possible to store the result of applying the function pointer to the object (Stroustrup p.419) You might think it would turn into a normal function pointer or something, but it doesn't. With base and derived with virtual functions, you may create a pointer to a member of the base class, apply it to a member of the derived class, and get the derived class' version of the function in question, as expected. VJ 424 has a detailed discussion on why things work the way they do. Note in particular that if you inherit from FOO1 and FOO2, and you call a FOO2 member function, the this pointer has to be adjusted to point to the FOO2 subobject, which might be after the FOO1. This adjustment amount has to be tracked behind the scenes as PART of the pointer to member function. Function Pointers: The linkage type (such as extern "C") is part of a function pointer. Implementations may, but are not required to, provide C++ linkage for functions from the C standard library (VJ 435). Some notes on the correspondence of C++ mechanisms to design goals: Inherit publicly from an abstract base class (one with pure virtual functions) to define an interface, the only way of doing so in C++. Meyers #32 talks about public inheritance meaning an is-a relationship. Model has-a with composition. For is-implemented-with, you can choose between private inheritance and composition. Meyers prefers composition whenever possible, using private inheritance only when access to private/protected data is needed, and for space reasons in dataless classes. G4 also points out that using composition allows for runtime changes of the underlying representation. The third option is templates. All of these address the same basic goal, and selection between them needs to be made based on second order effects. EXCEPTIONS ~~~~~~~~~~ Standard Exceptions: Everything is derived from std::exception in . The heirarchy, including things not used in the standard library, is: Exception bad_alloc (from new, in ) bad_exception (from exception specification, in ) bad_cast (from dynamic_cast, in ) bad_typeid (from typeid, in ) ios_base::failure (from ios_base::clear, in ) logic_error length_error domain_error out_of_range (used by bitset, in ) invalid_argument (used by bitset, in ) runtime_error range_error overflow_error (used by bitset, in ) underflow_error (Stroustrup 385, where he also says he doesn't personally like this framework.) The base exception has constructors, operator=, and a what() function which returns a char* with an explanation. Exception Specifications: C++ does have exception-specifications for functions, but they're different from Java's; the default is everything, not nothing. Also, there are not two inherent classes of exceptions. Exceptions which don't meet the promise get turned into std::unexpected, which by default calls terminate(). (Stroustrup 375). Overriding virtual functions must be at least as restrictive as the original. An exception specification is not part of the type of a function, and cannot be included in a typedef, but *is* a property of a function pointer. TEMPLATES ~~~~~~~~~ Terminology: A "member function template" is a function which has template paramters separate from the class. A "primary template" is anything that's not a partial specialization. It does not have another set of <> after the template<>. These are the only templates allowed for functions. A "template-id" is a template name followed by explicit arguments in <>. An "argument" is the thing which is substituted for a "parameter" when instantiating the template. A "qualified" name is one with a ::, ., or -> to the left of it. The enclosing scope is not used. A "dependent" name depends in some way on a template parameter. Things You Can't Do: Member function templates cannot be virtual. Only types, integral constants, addresses with external linkage can be template parameters. Unlike normal classes, class template names will conflict with variable names; they are not in a separate namespace. (VJ 99) Template parameters of template parameters cannot be used at the outer level. (see VJ 103) Templates cannot be declared inside a function (VJ 100) If all template arguments have a default value, empty brackets <> are still required. Unnamed or local classes/enum types may not be template arguments. Template Syntax Notes: For templatized member functions of templatized classes: template template Foo::Bar(method_template_param qux) { ... There could be more if there were nested clasess. (VJ 96) In template-templates, only the keyword "class" can be used; typename, and struct do not cut it (VJ 111). In the following example, typename is impermissible for the template-template, but class is OK: template typename C> class foo { }; ^^^^^^^^ Here's some horrible syntax with a nontype parameter that starts with "typename" anyway, in its *other* meaning: template Sometimes "template" is required in bizarre places when using dependent names (VJ 132): p.template Foo::f(); Template Argument Deduction: No automatic type conversion is allowed; each much match exactly. This differs from overloaded non-template functions. (Introduction VJ 13; details VJ 167) Most contexts are used for deducion, but qualified type names are not - Q::X will never be used to deduce T. Also, nontype expressions which are not just a parameter, such as S. (VJ 170) When taking the address of a template function, the type of the function pointer being assigned to is used in deduction. The following conversions can be used: * If the parameter was a reference, it may be more const/volatile qualified than the argument * If the argument is a pointer or pointer to member, it may be converted with qualification conversion * (Except for conversion operator template deduction), the parameter type used may be a base type of the argument. When matching NONTYPE parameters, user-defined and derived-to-base conversions are not considered. Default parameters in ARGUMENTS are not considered. For example, template class Container does not match std::list, because std::list has a second parameter. You might not notice that, since it has a default value and you almost never specify it, but it will cause it to not match. You'd have to respecify the default in the argument: template > class Container Name Lookup Rules: A name is "qualified" if its scope is specified with ::, ., or ->. A name is "dependent" if it depends on a template parameter. (VJ 120 for more detailed terminology) If a qualified name has the scope of a class, base classes are also searched, but enclosing scopes are not. Unqualified names look up through a heirarchy of enclosing scopes which is called "ordinary lookup" (VJ 121) Argument-dependent lookup adds scopes to unqualified names of nonmember functions, and is used only when ordinary lookup does not find anything. ADL is inhibited if the function to be called is enclosed in parenthesis, and is irrelevant if the function takes no arguments. If ADL is used, it looks up the name in namespaces and classes associated with the arguments. The rules are: * For builtin types, the empty set * For pointer and array types, those of the underlying type * For enum types, the namespace in which the enum is declared * For class members, the enclosing class * For class types, the class itself, the enclosing class, and any direct or indirect base classes. Also the namespace in which these associated classes are declared. If the class is a template instance, also the types of the template arguments and their classes and namespaces. * For function types, the namespaces and classes associated with all the parameter types and the return type. * For pointer-to-member, all those of the class plus those of the member. Using directives are ignored. (VJ 123-124) Friend declarations can be used to inject a name into the scope to be found by argument-dependent lookup (VJ 125). A class' own name is also injected within it for use as an unqualified name. Class templates are as well, and if not followed by template arguments, assume the parameters as arguments. (VJ 127) If a default argument is not used, it's not an error for it to refer to an invalid type or be impossible to construct (VJ 97). If the dependent name is a template, it will not be found; for example, foo<3>(xp) will not be found through its argument due to a catch-22 situation (VJ 135). Nondependent names are looked up at template declaration time; dependent names are looked up at instantiation time. Nondependent names are NOT looked up in dependent base classes to avoid inconsistency in the case of specialization (VJ 137). To work around this, make the name dependent with a this-> (can't be done for all types of things) or make it fully qualified in the base class (loses polymorphism). Instantiation: The basic concept is that two passes of parsing occur, one at declaration time and one at instantiation time. All the dependent names are not looked up until the latter time, and failure to resolve a type is not an error, but just removes that particular template from the list of candidates to match. (details at VJ 146) However, invalid expressions are in error; it is only nonexistent TYPES which are OK and only remove the candidate. Function Resolution: If a template and non-template function both match, the non-template is preferred. Failing that, the "most specialized" template is chosen for instantiation. If two or more versions at the highest level of matching specialization are equally specialized (both match and neither is a specialization of the other), there is a compile-time error. Implicit type conversions are never used on template parameters when looking up template functions like they are when looking up normal overloaded functions. With templates, the types must match exactly. This includes full specializations. However, for the function arguments themselves once the template parameters are deduced, lvalue conversions, qualification conversions, and conversions from derived to base will be performed. A function generated from a template is never equivalent to an ordinary function. This, it cannot override a virtual function, and it cannot be a default copy constructor or copy-assignment operator. One technique that can be used is to create a non-template friend function of a template class. Because this friend function is not a template, type conversions will be applied to make its arguments match. See Meyers #46, VJ 111, 176. If you can't substitute a template argument into a certain overloaded function template, that one is removed from the list of candidates, and there is no error. This is a key building block for all kinds of compile-time checks and hacks, especially when you add sizeof(). Most of this is the providence of the Alexandrescu book. See also "substitution failure is not an error", VJ 106, and note that invalid *expressions* still fail, only creation of invalid *types* is not an error. Overloaded Function Signatures 1. The unqualified name or name from the function template 2. The class or namespace scope; if internal linkage, the compilation unit 3. The const/volatile qualification, if a member function 4. The types of the function parameters (before template substitution) 5. The return type, if generated from a function template 6. The template parameters and arguments This has consequences such as the following being distinct: template void f1(T1, T2) template void f1(T2, T1) Of course overload resolution will never decide between them, but they could exist in two compilation units and the linker should work. In fact, they appear as: _Z2f1IiiEvT0_T_ and _Z2f1IiiEvT_T0_ but both deobfuscate to 'void f1(int, int)' in c++filt. Explicit Specialization: Full Specialization of Classes: A specialized version of a class can be completely different, with different member functions. Full specializations look like this: template class Foo; template<> class Foo {}; You can identify the "primary" template because it does not have the <> after the name. Methods and static members of fully specialized classes must *not* be preceded by template<>. It is an error to instantiate the general version in one translation unit and have a specialization in another (VJ 193) As a special case for template specializations, members can be declared without being defined outside the body of the class. There is a design flaw here which makes it impossible to define static members which have only default constructors (VJ 198). Full Specialization of Functions: Looks like this: template f(T) {} template<> f(int) {} template<> f(int) {} Often the specialized type can be omitted because it can be inferred from the function arguments, as in the third example above. It is *not* a template, thus only one definition must be provided; the specialization definition should thus not go in the header unless it is inline. Default arguments may not be specified again, but those from the template are used. Partial Specialization of Classes: look like this: template class Foo {}; template class Foo {}; template class Foo {}; The arguments must match in kind the primary. New default arguments are not permitted. The nontype arguments must be nondependent values or nontype template parameters; they cannot be dependent expressions (eg 2*N). The partial specialization must not be exactly identical to the primary. There can be more or fewer parameters than in the primary, as in the third example above. Partial Specialization of Functions: Is not possible. Use overloading instead, but note the following differences (VJ 214): With templates, only the primary is looked up first, and specializations only after it is selected; with overloading, all are considered together. It is possible to specialize member templates without changing the definition of the class, but this is not true of overloading. Overloading can break address-of operations on functions. Finally, friend declarations apply to a specific function template, and overloaded versions are not automatically included. Friends: Template instances cannot be defined, so a friend declaration of an instance cannot be a definition (VJ 11%). If there are no <> following, and the name is not qualified, it is not a template instance. It could the first declaration and/or a definition. If the name is qualified, it may not be the first declaration or a definition. If the friend is defined, it is imperative that the template parameters appear in it; otherwise it will be defined multiple times when you use the class with different template arguments (VJ 116). It is possible to use a friend template to indicate that all instances of a template are friends of the class. The Barton-Nackman trick, useful before overloaded function templates, was used to inject a normal function - not an instance of a function template - by declaring and defining it as a friend. This function then is not subject to template argument deduction but to regular overload resolution rules. However, because friend functions are NO LONGER unconditionally injected (they use to be), but found only through ADL, this trick is no longer useful - the whole point was to get a function which could apply conversions to its arguments, but if conversions are necessary, ADL won't find the function. (VJ 174-177). TEMPLATE DESIGN PATTERNS ~~~~~~~~~~~~~~~~~~~~~~~~ See also the separate patterns reference for non-language-specific patterns. Static Unbounded Polymorphism: Templates introduce a fundamentally different kind of polymorphism with different properties: Interface commonality is not required to be expressed through a common base class, but just by presence of methods with the correct signature. Generated code can be faster, because there is no vtable. Concrete types which have only partial interfaces will work fine if only those subsets are used. However, heterogenous collections do not work well, code size can be larger, and binary libraries generally cannot be made. (VJ 238) Building Blocks: A fundamental building block is to declare one function which requires a type that may or may not be possible to construct, and one which has ellipsis arguments (so it will always be the lowest priority), and then use sizeof() in some way to see what you get. From VJ 266: template class IsClassT { private: typedef char One; typedef struct {char a[2]; } Two; template static One test(int C::*); template static Two test(...); public: enum { result = sizeof(IsClassT::test(0))) == 1 } ; } The idea is that if you can construct a pointer-to-member for C, then C is a class, and you'll get the first function. If you can't, you'll get the second one. Because they have different size return types, you can then use sizeof() to figure out which one you got. Convoluted and unintentional though it may be, this is the stuff that template metaprogramming is made of. Here's another basic building block from VJ 272: template class IfThenElse; // note no definition // Then specialize for true and false template class IfThenElse { public: typedef Ta T; }; Void cannot be a reference or be a function argument (VJ 438). Traits and Policies: Traites templates have a bunch of typedefs, and then specializations so that the typedefs will do the right thing for various types. For example, they can be used to get the reference-type of a type, making it a no-op for a type which is already a reference, so you don't get a double-reference, which would be invalid (although this particular case is now special-cased in the language; VJ 269). As another example, traits based on two types can be used to figure out what the result type of combining them should be, traditionally a hard problem with templates. Consider also a policy trait which says how to pass read-only parameters - by const reference or by value, whichever ends up being faster. See VJ 277 for an implementation and discussion; one disadvantage is that argument deduction no longer works. Other ideas include the best way to copy and swap (VJ 279), Named Policy Arguments: Instead of having each argument be different, accept a long list of "policy setters". They then take a template class definining which policy they're setting, and whose argument is the policy it should be set to. (VJ 285) The PolicySetter derives from an intermediate base class (necessary because you can't have the same class multiple times as a direct base, only indirect), which then derives virtually from a Policy_Is or DefaultPolicyArgs class, both of which derive from the same default base. This relies on the Domination Rule, which allows a typedef in a derived class to hide that in the base class. Empty Class Optimization: A class in C++ must have size of at least 1 byte, even if it has no members and exists just to provide types, so that it is possible to check whether two pointers are to the same object. However, base classes may have no space allocated provided this does not cause it to be allocated at the same address as another object of the same type (not all compilers necessarily implement this). See VJ 290. This matters in practice because you may have classes which inherit from the same typedef-bearing classes through multiple paths, and cost a byte each. The same optimization does not exist for data members, which may motiate making things base classes instead, but this has many problems of its own (VJ 293). One compromise is to merge the possibly empty type into another real data member. "Curiously Recurring Template Pattern": Pass a derived class as a template argument to one of its own base classes: template class Base { ... }; class Foo : public Base { ... }; This also works with dependent bases: template class Base { ... }; template class Bar : public Base > { ... }; or even: template class Derived> class Base { ... }; template class Baz : public Base { ... }; It is useful to factor out implementations of interfaces that can only be member functions, because they require constructors/destructors/operators. (VJ 295-298) Smart Pointers: VJ has reference-counting pointers on page 379. On 391 there is a discussion of how conversion to bool will allow undesirable things like arithmetic, but how conversion to pointer-to-member gets the right semantics for comparison to null. Parameterized Virtuality: By deriving from a base which is a template parameter, certain functions might be virtual or might not. This can be used to control whether they are virtual by having bases which differ only in that one of them declares the function as virtual. (VJ 298) This seems to have few known practical applications. Tuples: One implementation is given in VJ around page 401; Alexandrescu does it differently. Functors: VJ 422 has some interesting general description of function types. It notes in particular that some implementations will return the name of the typedef when using typeid() functionality, but this is not required. Also, it notes that references to functions exist, but are almost never used. A "callback" is distinct in that it passed as a function call argument and not a template parameter (VJ 417). A functor must be an object, so a function pointer is a functor (it can be called just like a function), but a reference to a function is not. Functors can be given as template type arguments (in which case they can't have state), as function call arguments, or a hybrid in which the default argument to the function comes from the type. The one thing that doesn't work is using non-type template arguments, because they must match exactly and won't match derived classes or casts (VJ 429-432). There is a complete implementation in VJ, culminating with value binders on page 457. METAPROGRAMMING ~~~~~~~~~~~~~~~ Basic Building Blocks: The most fundamental idea is recursive template instantiation with a specialization to end the recursion. Note that enumeration values are rvalues, whereas constant integers are lvalues. This makes the former more desirable, because the latter require the compiler to instantiate them at a real memory address. Using ?: in the enum will result in the instantantion of both branches (VJ 307). Instead, use the IfThenElse template building block mentioned above. Square Root Example: Here's an example which does a binary search to find the square root of a number: template class Sqrt { public: enum { mid = (LO + HI + 1/2 }; typedef typename IfThenElse< (N, Sqrt >::ResultT SubT; enum { result = SubT::result }; }; template class Sqret { public: enum { result = S }; }; Unrolling Loops: See VJ 316 for an example of unrolling a loop to compute dot products with recursive templates. This is used in the Blitz++ numerical library. Deferring Loop Operations: See VJ 328 for an example of operators that return placeholders which are then turned into ONE evaluation with a special operator= after everything is combined. REFERENCES ~~~~~~~~~~ Stroustrup The C++ Programming Language, 3rd ed Meyers Effective C++, 3rd ed C++N C++ in a Nutshell, 1st (only) ed VJ C++ Templates, Vandevoorde and Josuttis Alx Modern C++ Design, Alexandrescu vim: tw=75 ai