Making Common Mistakes Legal
It's frustrating to have to add spaces between ">" symbols when you're wrapping up a declaration that involves nested templates. Many people's natural instinct is to jam them all together:
std::vector<std::pair<int, std::string>> vect;
Today, that's illegal: The two ">" symbols at the end are treated as a shift-right, and the declaration is ill-formed. In the next version of the Standard, that will be legal. As long as you're unwinding template IDs, a non-nested ">>" is treated as two ">"s and not as a single token. This means that you have to be a little careful if you really want to have a shift-right somewhere in your template usage, but that's far less common. For example, the working draft of the new Standard gives this example of code that will be invalid:
template <int i> class X { /* ... */ }; template <class Ty> class Y { /* ... */ }; Y<X<6>>1>> x4;
To make it valid, you have to put parentheses around the arithmetic expression:
Y<X<(6>>1)>> x4;
Another common problem occurs when template code uses a type name inside a friend declaration. Technically, the type name has to be what the Standard calls an "elaborated type specifier." That makes this usage illegal:
template <class Ty> class no_children { // template to block inheritance from Ty no_children() {} friend class Ty; }; class final : virtual no_children<final> { /* ... */ };
If it worked, this pattern would prevent deriving from the class final [4]. There's a problem, though: In the declaration friend class Ty, the name Ty is not an elaborated type specifier, so it can't be the target of a friend declaration. That's been changed, so that a broader range of syntactic elements can be used as the target of a friend declaration, and this code will be legal.
A common beginner's mistake is writing something like this:
struct S { S() : i(0), j(0) {} S(int j0) { S(); // mistake j = j0; } int i, j; };
The mistake is thinking that the line marked "mistake" applies the default constructor to the object being constructed, thus setting i and j to 0. Of course, we've all learned to patiently explain that what that line actually does is create an unnamed temporary object of type S, and immediately destroy it. That will still be a mistake, but there is a new syntax that allows a constructor to delegate part or all of its work to another constructor:
struct S { S() : i(0), j(0) {} S(int j0) : S() // changed { j = j0; } int i, j; };
The line marked "changed" has a constructor as its initializer list. That tells the compiler to apply that constructor first, and then to execute the body of the constructor being defined [5].