When the first edition of the Annotated C++ Reference Manual was written, it introduced Templates to the C++ world. The notation of using the < and > brackets was used because Bjarne felt like it would probably be easier to parse because () was already overloaded. He said later that he realized that using () would not have been that bad, but it was already too late. As a result of this oddity was put into the language:
typedef std::vector< std::vector< int > > type1; // Okay
typedef std::vector< std::vector< int >> type2; //Error
It becomes a more difficult problem to fix when you remember that the compiler front end is usually done in stages. First the compiler does lexical analysis to break the program into tokens, then does syntax analysis to check the grammar, and then does the type checking. Usually at that point it has an abstract syntax tree that is passed off to the compiler back end. I know this is a simplification and many compilers will blur each of these stages, but this model should work.
When the lexical analysis is being done, the tokens are broken up into the longest match, that is why long inta gives you a long named "inta" and not a long int named "a". This is usually called "Maximum Munch"
in [n1757] there were three alternative suggestions to fix this problem. Here they are, out of order.
Proposal 3
Get rid of the >> token. This makes a single > the maximum munch. It would also mean that a right shift operation would be two > tokens, so inta > > 3 would be a valid right shift operation. This approach was suggested just for the sake of completeness in the submission, not because anyone would actually want to do it. It causes too many other technical complications and it just looks funny.
Proposal 1
Keep the >> as its own token, but decree that if there is an open < token, then the >> token will be counted as two closing > tokens. This seems like the obvious solution, but it does have an unintended backwards compatibility side affect. Consider the following program
#include <iostream>
template%ltint I&rt struct X {
static int const c = 2;
};
template<> struct X<0> {
typedef int c;
};
template<typename T> struct Y {
static int const c = 3;
};
static int const c = 4;
int main() {
std::cout << (Y<X<1> >::c >::c>::c);
std::cout << (Y<X< 1>>::c >::c>::c);
}
Under the current rules this outputs 03, but under this proposed change this program would output 00 because the right shift operator turns into the closing template brackets.
Proposal 2
GCC and EDG C++ has implemented a variation of Proposal 1 for error recovery purposes. It treats the >> as right shift if it can, but otherwise uses it to close the template arguments. This means A<B<int>> would be valid but A<B<1>> would still be invalid. This solution would only partly fix the problem, and leave an even more archaic one in its place.
Solution:
The committee went with Proposal 1. See 14.2/2 of the spec for the official wording of the change. This also applies to the <...> in the casting operators. It is worth pointing out that a similar issue can come up when using the >>= or even the >= operators, although using that in a template type declaration would be so uncommon that they decided not to do anything about it at this time.
No comments:
Post a Comment