Should the function template name be visible when looking for the name preceding ::?

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 states that searching for the name of a name preceding :: only considers namespaces, types, and patterns whose specialization is types. "Are clang and gcc right to reject this code? If so, what am I missing?

From C ++ Working draft standard n3337

3.4.3 Qualified Name Search [basic.lookup.qual]

The name of a member of a class or element of a namespace or enumerator can be passed after the permission :: scope statement (5.1), applied to the nested qualifier name, which denotes its class, namespace or enumeration. If :: the scope operator in the nested qualifier is not preceded by the decltype-specifier, the search for the name preceding this :: considers only namespaces, types and templates whose specialization is types . If the name found does not indicate a namespace or class, enumeration or dependent type, the program is poorly formed.

14.2 Names of specialized templates [temp.names]

In order for the template name to be explicitly specified by the template arguments, the name must be known in order to refer to the template .

After searching for the name (3.4), it finds that the name is the name of the template or that the operator-function-identifier or identifier of the operator-literal refers to a set of overloaded functions, any member that is a function template , if it follows a < , < always accepted as a delimiter of a list of argument templates and never less than an operator .

Edit

To avoid confusing this problem with ambiguity between expression and declaration, here is the source code with 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 leads to the same error in all cases. < cannot be interpreted as an operator.

ambiguous uniquely the name of the template, but can be either a type or a function. You can parse the entire template identifier without knowing whether it calls a function or type, and resolve the ambiguity later. Does this justify execution as standard?

+8
c ++ language-lawyer templates
source share
2 answers

The problem is that the paragraph you quoted ends up being applied too late. Before getting there, the compiler must determine that in ambiguous<3>::value values < and > delimiters of the template arguments, and not more and less than. (Consider:

 int ambiguous; int value: // ... int i = ambiguous<3>::value; 

which parses as (ambiguous < 3) > ::value , where < and > less and more, respectively.) This includes finding ambiguous as an unqualified name and attaches the character to N::ambiguous . You were subsequently stuck with an instance of the N::ambiguous<3> template to the left of :: , which is not legal.

EDIT:

This problem is not as clear as we would like: only the standard refers to section 3.4 in section 14.2, where he discusses this, and in section 3.4 all possible rules for the name Look are discussed. On the other hand, there is only one way to interpret it: the compiler cannot parse anything until it knows if it calls an ambiguous template or not, and can decide whether the next one < larger or a list of template arguments opens. And, of course, he cannot “reconfirm” later, after he has analyzed the following tokens, since in the general case the ligation can change the meaning of < , invalid parsing. In practice, although the standard does not say as clearly as it should be, the search for the name in this case should be an unqualified search for the name (or a member of the access class if the name is preceded by the operator . Or -> ).

+8
source share

Samples in the internal namespace hide the names of external ones.

 template<int i> struct A { static const int value = 0; }; struct B { static const int value = 0; }; typedef A<0> C; namespace N { // The local function A is not declaced, yet, but the global A is: int early_e = A<3>::value; // Ok: The A in the global namespace. [simple-template-id} template<int i> int A() { return 0; } int B() { return 0; } int C() { return 0; } int a = A<3>(); // Ok: The A in the namespace. [simple-template-id} int b = N::A<3>(); // Ok: The A in the namespace. [N::simple-template-id] int c = ::N::A<3>(); // Ok: The A in the namespace. [::N::simple-template-id] int d = ::A<3>::value; // Ok: The A in the global namespace. ::simple-template-id::identifier] // The local function A is no type: "templates whose specializations are types" int e = A<3>::value; // Error: The namespace has the function name A, // which hides the global A. [simple-template-id::identifier] // The local function B is no type, but the global B is a type: int f = B::value; // Ok: The B in the global namespace. [class-name::identifier] // The local function C is no type, but the global typedef C is a type: int g = C::value; // Ok: The C in the global namespace. [typedef-name::identifier] } int main() { return 0; } 
+3
source share

All Articles