According to the C++ Standard, function parameter's name is parsed by a declarator-id, and a declarator-id can also be a qualified name. That means, the following code is perfectly valid (if I've understood the relevant sections from the Standard correctly):
template<class T>
struct Sample
{
int fun(int T::count); //T::count is qualified variable name
};
My question basically is, why would anyone write such code? In what situations, the use of qualified name (in function parameter-list) can be advantageous?
EDIT:
It seems I understood the sections incorrectly. Instead of the above code, we can probably write the following code (as per the C++ standard):
template<class T>
struct sample
{
void fun(int arr[T::count]);
};
gcc-4.3.4 compiles it perfectly. But then, I'm not totally satisfied, because T::count is not a parameter anymore (I guess).
It's invalid. The syntax allows arbitrary declarators, but 8.3.5p8 says
An identifier can optionally be
provided as a parameter name; if
present in a function definition
(8.4), it names a parameter (sometimes
called “formal argument”)
Edit Another quote which syntactically constraints declarators (8.3p1, [dcl.meaning]):
Each declarator contains exactly one
declarator-id; it names the identifier
that is declared. The id-expression of
a declarator-id shall be a simple
identifier except for the declaration
of some special functions (12.3, 12.4,
13.5) and for the declaration of template specializations or partial
specializations (14.7). A declarator-id
shall not be qualified except for the
definition of a member function (9.3)
or static data member (9.4) or nested
class (9.7) outside of its class, the
definition or explicit instantiation
of a function, variable or class
member of a namespace outside of its
namespace, or the definition of a
previously declared explicit
specialization outside of its
namespace, or the declaration of a
friend function that is a member of
another class or namespace (11.4).
So in a parameter declaration, you must not use qualified names.
Edit: In the edited form, the function parameter type decays to an int*, even before a test is being made whether T::count actually exists and is an integer constant. If you want an example where a qualified name in such a signature would do something meaningful, consider
template<class T>
struct sample
{
void fun(int S=T::count);
};
When fun gets called without parameter, the compiler needs to determine the default argument, which then fails if T does not have a count member, or that cannot be converted to int.
As far as I understand your code is ill formed because
$8.3/1 : When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers, and the member shall not have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id. [Note: if the qualifier is the global ::scope resolution operator, the declarator-id refers to a name declared in the global namespace scope. ]
P.S: I am not 100% sure. Please correct me if I am wrong. :)
In what situations, the use of qualified name (in function parameter-list) can be advantageous?
Read Items 31 and 32 from Exceptional C++ by Herb Sutter. Both the items deal with Koenig lookup and the Interface principle.
It seems I understood the sections incorrectly. Instead of that code, we can probably write the following code (as per the C++ standard):
template<class T>
struct sample
{
void fun(int arr[T::count]);
};
gcc-4.3.4 compiles it perfectly. But then, I'm not totally satisfied, because T::count is not a parameter anymore (I guess).
Related
In the following definition of template struct B, a lambda is used as a default value of a non-type template argument, and in the body of the lambda some type A is defined:
template <auto = []{ struct A{}; }>
struct B {};
Clang and MSVC are fine with this definition, but GCC complains:
error: definition of 'struct<lambda()>::A' inside template parameter list
Demo: https://gcc.godbolt.org/z/f1dxGbPvs
Which compiler is right here?
[temp.param]/2 says:
Types shall not be defined in a template-parameter declaration.
Taking this as written, GCC is correct to reject this code: this prohibition is not constrained to type-id of a type parameter, but applies to anywhere within template parameter declaration. Including nested within a lambda.
This sentence was added as a result of DR 1380 (N3481), which reveals it was considered already implied by what now I am guessing to be [dcl.fct]/17:
Types shall not be defined in return or parameter types.
This, however, only seems to apply to the type of the parameter declared and not to the initializer-clause.
On the other hand, one might also read it as prohibiting lambdas themselves in template parameters. After all, a lambda expression implicitly defines a class type ([expr.prim.lambda.closure]/1).
On the third hand, we also have [expr.prim.lambda.closure]/2, which states:
The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression.
The relevant scope here seems to be the namespace scope. This would imply the lambda should be treated as if its type were declared outside the template parameter list. But then, so should be declarations inside the body of the lambda, and the definition in the question should be allowed.
Personally, I consider it a defect in the standard that the scope of this prohibition seems so ill-defined.
#include <iostream>
template<class T>
struct A{
int c = T::a;
};
struct B{
A<B> cc;
static const int a = 0;
};
int main(){
}
GCC and Clang both accept the above example. Regarding how the lookup rule applies to a name in a class template specialization, which might be a member of a class that causes the implicit instantiation of the class template specialization is not clear in c++20 or before. Fortunately, it's clear in the current draft.
[basic.lookup#class.member.lookup-3]
The declaration set is the result of a single search in the scope of C for N from immediately after the class-specifier of C if P is in a complete-class context of C or from P otherwise. If the resulting declaration set is not empty, the subobject set contains C itself, and calculation is complete.
It seems that the rule can be used to interpret most cases that I said in the above, however, consider the above example, it's a bit special.
The definition of non-static member cc would cause the implicit instantiation of specialization A<B>, at this point, it's not the complete context of class B. Hence, the subsequent lookup for a name in the scope B should be from this point. If T::a is used as the type-specifier of a non-static member of class template A, It's 100% sure that the compiler would report an error that says no identifier a can be found in the scope of B.
However, except for the following rule
temp.res#general-1
If the name is dependent (as specified in [temp.dep]), it is looked up for each specialization (after substitution) because the lookup depends on a template parameter.
I cannot find any wording in the standard that states whether an implicit instantiation of A can cause the lookup rule to be applied to the name within the default member initializer or is not at that point.
At first glance of the above rule, It should mean that the lookup should be performed for the name when the enclosing class template specialization is instantiating, then a cannot be found in the scope of B since it's not deemed as a complete class at that point and only these declarations that are reachable at point P can be found.
Obviously, the behavior of GCC and Clang consider T is a complete type such that a can be found in T. In other words, it seems that these compilers do not immediately perform the lookup for T::a when A is instantiating. If I miss a certain special rule, please point them out.
Suppose we have this code, copied from a separate question:
namespace x
{
void f()
{
}
class C
{
void f()
{
using x::f;
f(); // <==
}
};
}
The name f on the indicated line unambiguously refers to x::f (at least according to both gcc and clang). Why is x::f preferred over x::C::f in this case? Shouldn't it be ambiguous as both names are visible?
Because the using declaration brings x::f into the scope of f, which is narrower than that of C. Unqualified lookup considers the local block scope, finds a match, and stops before considering the wider class scope. There is no argument-dependent lookup since there are no function arguments, so no further scopes are considered.
#MikeSeymour's answer is spot on; here are the relevant standard quotes (C++11, emphasis mine):
13.3.1.1.1/3:
In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form
of a primary-expression. The name is looked up in the context of the function call following the normal rules
for name lookup in function calls (3.4). The function declarations found by that lookup constitute the set of
candidate functions. Because of the rules for name lookup, the set of candidate functions consists (1) entirely
of non-member functions or (2) entirely of member functions of some class T. ...
3.4.1/1:
In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the
respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is
found, the program is ill-formed.
3.4.1/8
A name used in the definition of a member function (9.3) of class X following the function's declarator-id
... shall be declared in one of
the following ways:
before its use in the block in which it is used or in an enclosing block (6.3), or
shall be a member of class X or be a member of a base class of X (10.2), or
...
From 3.4.1/8, we see that a declaration for the name f (such as the declaration using x::f;) in the block in which it's used is listed earlier than f as the member of class C. As per 3.4.1/1, the earlier one is chosen, so the entire lookup resolves to x::f introduced by the using declaration.
I think that these quotes from the C++ Standard will be relevant:
From the C++ Standard (7.3.3 The using declaration)
13 Since a using-declaration is a declaration, the restrictions on
declarations of the same name in the same declarative region (3.3)
also apply to using-declarations.
And (3.3.7 Class scope)
4) A name declared within a member function hides a declaration of the
same name whose scope extends to or past the end of the member
function’s class.
#include <iostream>
using namespace std;
struct test
{
test(){cout<<"class"<<endl;}
};
void test(){cout<<"function"<<endl;}
int main()
{
test();
return 0;
}
Output:
function
(VS2013 ang gcc 4.8.1)
Why function is selected? Isn't it ambiguity?
This is called name hiding and described in
3.3 Scope [basic.scope]
3.3.1 Declarative regions and scopes [basic.scope.declarative]
4) Given a set of declarations in a single declarative region, each of
which specifies the same unqualified name, — they shall all refer to
the same entity, or all refer to functions and function templates; or
— exactly one declaration shall declare a class name or enumeration
name that is not a typedef name and the other declarations shall all
refer to the same variable or enumerator, or all refer to functions
and function templates; in this case the class name or enumeration
name is hidden (3.3.10). [...]
emphasis mine.
Note that changing the order of declaration doesn't affect the outcome:
void test(){cout<<"function"<<endl;}
struct test
{
test(){cout<<"class"<<endl;}
};
int main()
{
test();
return 0;
}
still prints out function.
In case it isn't obvious, don't do this :)
From N3485 §3.3.10 [basic.scope.hiding]/2:
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member,
function, or enumerator declared in the same scope.
Therefore, the function takes precedence over the class.
As mentioned in the comments, the class is still accessible via the class or struct keyword. If the class took precedence, the function would be unreachable.
I'm not certain either of the previous responses are the "why" for your particular instance.
Don't get me wrong; They are true and accurate.
I just think it's simpler.
In your example, you never instantiate the struct.
In other words, you declared it, but you never used it.
Since you never referenced it, it is never called.
Name precedence and such don't really apply here, since you never instantiated the struct.
Hope this helps,
-john
I'm working on a source editor for C++ and came up with simple optimization that I do not need to invalidate (e.g. highlighting, rebuild AST, do static analysis) the code before the currently edited statement (basically, before the previous semicolon/closing brace) but I am not sure if this is always true for C++.
E.g. in Java it is possible to call functions declared/defined after the edit location. Hence, if the user adds an argument to the function then error marker should be placed in the code before the edit location. In C++ function should be declared before it is used (and if the declaration does not match definition the error will be on definition).
Member function bodies defined inline in the class will be conceptually (and actually, in the compilers I know) parsed at the end of the class and can thus access members of the class declared after them.
Templates are compiled in two phases. The first phase is where they're defined, the second where they're instantiated. The current compilers can blame you for template errors at the point of instantiation, when substituting the actual arguments leads to an error in the template.
It would be entirely reasonable for your editor to follow the same logic. If the template definition looks good when you see it, it passes the first phase. When the code being edited instantiates a template, re-check, and blame any errors in the second phase on the instantiation.
This hints at a more fundamental problem. Where do you say an error occurred? The C++ standard doesn't care. As far as it's concerned, "syntax error somewhere" is a sufficient diagnostic. So, if there's an inline method trying to access a non-existing member this->a, you can claim there's an error in the method. But with equal validity, you can claim at the final }; that the class failed to define the necessary member a.
The underlying cause of all these errors is that two pieces of code must agree on something. When they don't, you can choose who to blame. For your editor, you could blame the fragment which came last. It's just a matter of getting the diagnostic wording right.
In general, outside a template definition, the rules for name lookup in C++ require a name to be declared before the point at which it is used. Your idea would therefore work in most cases. Unfortunately - as pointed out by SebastianRedl - there is a special case in which this rule of thumb does not apply.
Within a class definition, the declarations of all members of the class (and its enclosing class(es)) are visible during name lookup within the body of a member function (including a ctor-initializer-list or exception-specification), or in a default argument of a member function.
An illustration:
struct A
{
struct B
{
static void f(int i = M()) // uses 'A::M' declared later
{
A::f(); // calls A::f(int) declared later
}
};
static void f(void*)
{
f(); // calls A::f(int) declared later
}
static void f(int i = M()) // uses 'M' declared later
{
}
typedef int M;
};
If the token that was modified occurs within a member function-body or a default argument, you would have to reparse all classes that enclose the token.
From C++ Working Draft Standard N3337:
3.4.1 Unqualified name lookup [basic.lookup.unqual]
A name used in the definition of a member function (9.3) of class X following the function’s declarator-id
or in the brace-or-equal-initializer of a non-static data member (9.2) of class X shall be declared in one of
the following ways:
— before its use in the block in which it is used or in an enclosing block (6.3), or
— shall be a member of class X or be a member of a base class of X (10.2), or
— if X is a nested class of class Y (9.7), shall be a member of Y, or shall be a member of a base class of Y
(this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class), or
— if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block
enclosing the definition of class X, or
— if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class
or a nested class within a local class of a function that is a member of N, before the use of the name,
in namespace N or in one of N ’s enclosing namespaces.