Should the name of a function template be visible during lookup of a name preceding ::?
c++, language-lawyer, templates
Solution
The problem is that the paragraph you quote ends up being applied too late. Before getting there, the compiler must determine that in `ambiguous<3>::value`, the `<` and `>` are template argument delimiters, and not greater than and less than. (Consider:
int ambiguous;
int value:
// ...
int i = ambiguous<3>::value;
, which parses as `(ambiguous < 3) > ::value`, where the `<` and `>` are less than and greater than, respectively.) This involves a lookup of `ambiguous` as an unqualified name, and binds the symbol to `N::ambiguous`. Afterwards, you're stuck with the instantiated template `N::ambiguous<3>` to the left of `::`, which isn't legal.
EDIT:
This issue isn't as clear as one might like: the standard only refers to section 3.4 in section 14.2, where it discusses this, and section 3.4 discusses all of the possible rules of name lookup. On the other hand, there is really only one way to interpret it: the compiler cannot parse anything further until it knows whether `ambiguous` names a template or not, and can decide whether the following `<` is greater than, or opens a template argument list. And of course, it cannot "rebind" the argument later, once it has parsed the following tokens, since in the general case, rebinding could change the meaning of the `<`, invalidating the parse. In practice, although the standard doesn't say so as clearly as it probably should, the name lookup in this case must be unqualified name lookup (or class member access, if the name is preceded by a `.` or a `->` operator).
Problem
Both clang and gcc reject this code: ``` template<int i> struct ambiguous { static const int value = i; }; namespace N { template<int i> void ambiguous(); int i = ambiguous<3>::value; // finds the function template name } ``` However, they both accept the following code: ``` struct ambiguous { static const int value = 0; }; namespace N { void ambiguous(); int i = ambiguous::value; } ``` The standard says that name lookup of a name preceding `::` "considers only namespaces, types, and templates whose specializations are types". Are clang and gcc correct in rejecting this code? If so, what am I missing? From C++ Working Draft Standard n3337 3.4.3 Qualified name lookup [basic.lookup.qual] The name of a class or namespace member or enumerator can be referred to after the :: scope resolution operator (5.1) applied to a nested-name-specifier that denotes its class, namespace, or enumeration. If a :: scope resolution operator in a nested-name-specifier is not preceded by a decltype-specifier, lookup of the name preceding that :: considers only namespaces, types, and templates whose specializations are types. If the name found does not designate a namespace or a class, enumeration, or dependent type, the program is ill-formed. 14.2 Names of template specializations [temp.names] For a template-name to be explicitly qualified by the template arguments, the name must be known to refer to a template. After name lookup (3.4) finds that a name is a template-name or that an operator-function-id or a literal-operator-id refers to a set of overloaded functions any member of which is a function template if this is followed by a `<`, the `<` is always taken as the delimiter of a template-argument-list and never as the less-than operator. Edit To avoid confusion of this issue with the ambiguity between an expression and a declaration, here is the original code with the templates using a type parameter instead of a non-type parameter. ``` template<class> struct ambiguous { static const int value = 0; }; namespace N { template<class> void ambiguous(); int i = ambiguous<int>::value; // finds the function template name } ``` This results in the same error in all cases. The `<` cannot be interpreted as an operator. `ambiguous` is unambiguously a template-name, but could either be a type or a function. It's possible to parse the entire template-id without knowing whether it names a function or a type, and resolve the ambiguity later on. Does the standard excuse the implementor from doing this?