You would need to skip anything inside of ()
brackets.
You need to look at the identifier before the <
and know if it's a type name or not.
This second one is the problematic one, you need to scan through all your source code and identify all the names of class/struct/union
s and typedef
s so that when you reach an expression of the form __w < __a
(simplified for this example) you know whether or not __w
names a type.
The reason this gets problematic is if you encounter any Preprocessor Metaprogramming (like Boost's library on the subject) you're basically stuck writing a program that can evaluate these to see what type names were created.
Furthermore, consider this piece of code (a little more complicated than necessary to show how hard it is):
template <template <class> class T>
struct Base
{
template <class X>
using type = T<X>;
};
template <>
struct Base<std::numeric_limits>//Let's assume numeric_limits only has one template argument for this example
{
static const int type = 0;
};
template <class T, Base<T>::type < 0>
struct OtherClass{};
This kind of complexity is what the typename
keyword is for, since Base<T>
is a dependent scope, you can't tell right away whether Base<T>::type
names a type or a member variable. In this way the grammar requires that Base<T>::type
be a static member variable and typename Base<T>::type
be a type (we don't know what kind of type, but that's okay we're only trying to find the end of the template identifier list).
Further to the example above you also need to handle the lesser known use of the template
keyword. Since Base<T>
is a dependent scope, how do you parse Base<T>::type<0>
? This depends on what type
is. The grammar, in this case, requires that Base<T>::type
be a member variable and be parsed as (Base<T>::type < 0) >
, and Base<T>::template type<0>
is a template expression.
The keywords typename
and template
, while difficult to wrap your mind around until you understand dependent scopes, make your job easier for you in the end. Otherwise, the simple question of where does a template identifier list end becomes nigh-impossible to answer without writing a full compiler (and even then the compiler is much more difficult to write).
Dependent scopes aside, you still need to be able to handle non-dependent scopes. This means you need to know whether Base<numeric_limits>::type
is a type or not, which means scanning every struct/class/union
for typedef
s and resolving public inheritance for base class typedef
s and private inheritance + using
statements.
If you restrict yourself to code that compiles, your job remains tractable, otherwise you have a lot more work ahead of you.
I don't promise this is everything, only that this will in all likelihood keep you busy for a while.