I have a simple template example that is as follow:
template<class T> class A {
friend int f(T);
}
int main(){
A<int> a;
return 0;
}
That code compile and execute without warning in VS2008 (except for the unused variable). I believe there should be a problem since we obtain many versions of a non-template function in the same class with only one definition. Did I miss something?
Why should this code produce an error? For every T you instantiate A with, a new function will be declared and friended. There will never be two identical functions, since you can't instantiate a template twice for the same type (you will just reuse the old instantiation).
Also, even if it was somehow possible to generate two equal declarations, there would be no ambiguity, since the functions are first declared inside the class. As such, they can never be found by anything other than argument dependant lookup. (Basically, those functions are useless as they cannot be called)
§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
Also, see this.
According to the C++ standard, the degree of syntax checking for unused template functions is up to the implementation. The compiler does not do any semantic checking—for example, symbols are not looked up.
Related
Consider the following class template, which contains two (hidden) friend declarations of the same friend (same function type; see below), which also defines the friend (and the friend is thus inline), but with the definition conditional on (mutually exclusive) requires-clauses:
#include <iostream>
struct Base {};
template<int N>
struct S : public Base {
friend int foo(Base&) requires (N == 1) { return 1; }
friend int foo(Base&) requires (N == 2) { return 3; }
};
[dcl.fct]/8 states that trailing requires-clauses are not part of a function's type [emphasis mine]:
The return type, the parameter-type-list, the ref-qualifier, the cv-qualifier-seq, and the exception specification, but not the default arguments ([dcl.fct.default]) or the trailing requires-clause ([dcl.decl]), are part of the function type.
which means that the two definitions above is an ODR-violation for a case where both definitions are instantiated; if we only focus on a single translation unit, [basic.def.odr]/1 would be violated:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, template, default argument for a parameter (for a function in a given scope), or default template argument.
and in a single TU this violation should arguably be diagnosable (no "need" for "ill-formed, NDR"). I'm trying understand the rules for when the definitions above will be instantiated; or if this is entirely implementation-defined (or even ill-formed before reaching instantiation phase).
Both Clang and GCC(1) accepts the following program
// ... as above
// (A)
int main() {
S<1> s1{};
std::cout << foo(s1); // Clang & GCC: 1
}
For programs (B) through (D) below, however, Clang accepts them all whereas GCC rejects them all with a re-definition error:
// (B)
int main() {
S<1> s1{};
S<2> s2{}; // GCC: re-definition error of 'foo'
}
// (C)
int main() {
S<1> s1{};
S<2> s2{}; // GCC: re-definition error of 'foo'
std::cout << foo(s1); // Clang: 1
}
// (D)
template struct S<1>;
template struct S<2>; // GCC: re-definition error of 'foo'
int main() {}
It's only when actually trying to invoke the friend function via ADL on both specializations that Clang actually emits an error
// (E)
int main() {
S<1> s1{};
S<2> s2{}; // GCC: re-definition error of 'foo'
std::cout << foo(s1); // MSVC: ambiguous call
std::cout << foo(s2);
// Clang error: definition with same mangled name
// '_Z3fooR4Base' as another definition
}
and we may note that only MSVC actually reaches a state of seemingly accepting both definitions after which it fails as expect ("ambiguous call").
DEMO.
Question
Can hidden non-template friend functions of class templates (friend declarations where the friends are also defined in the class) be overloaded only by a difference in (mutually exclusive) requires-clauses?
And, thus, which compiler is right here?
All (ill-formed NDR and/or implementation defined w.r.t. point of instantiation rules),
GCC
Clang
MSVC
None (example (E) is well-formed)
I have not been able to understand what rules that governs when a friend function declaration (of a class template) that is also a definition, is instantiated, particularly when requires-clauses are involved; possibly this is irrelevant, though, if the behaviour of GCC and Clang above are both incorrect.
(1) GCC HEAD 11.0.0, Clang HEAD 12.0.0.
From over#dcl-1,
Two function declarations of the same name refer to the same function if they are in the same scope and have equivalent parameter declarations ([over.load]) and equivalent ([temp.over.link]) trailing requires-clauses, if any ([dcl.decl]).
[Note 1: Since a constraint-expression is an unevaluated operand, equivalence compares the expressions without evaluating them.
[Example 1:
template<int I> concept C = true;
template<typename T> struct A {
void f() requires C<42>; // #1
void f() requires true; // OK, different functions
};
— end example]
— end note]
I understand there is 2 different foo (so no ODR violations) because of the differing requires clauses.
I think there is issue with all mentioned compilers to not cover this corner case.
Different trailing requires-clauses distinguish declarations of hidden friends for different specializations from eachother
Clang and GCC are both wrong to reject the program. As pointed out in #Jared42:s answer, [over.dcl]/1 should likewise apply for hidden friend declarations, such that the declarations in the OP:s example declare different friend functions.
Associated Clang bug report:
Bug 48872 - Rejects-valid for overloaded hidden non-template friend functions with mutually exclusive requires-clauses
Associated GCC bug report:
Bug 98822 - Rejects-valid: instantiation of class template instantiates (all) constrained non-template friend definitions (, even those) with unsatisfied constraints
Details
GCC is wrong by violation of
[temp.friend]/9:
A non-template friend declaration with a requires-clause shall be a definition.
A friend function template with a constraint that depends on a template parameter from an enclosing template shall be a definition.
Such a constrained friend function or function template declaration does not declare the same function or function template as a declaration in any other scope.
It was not clear to me at first that this separates friend declarations with specialization-exclusive requires-clauses, but as commented by the author of the paragraph (Hubert Tong; see details below), this is the intent of the paragraph:
[...] the "does not declare" wording is meant to say that the friends declared by each specialization is unique.
Clang is wrong by violation of [defns.signature.friend], which includes a trailing requires-clause (if any) in the signature of a non-template friend function [emphasis mine]:
⟨non-template friend function with trailing requires-clause⟩ name, parameter-type-list, enclosing class, and trailing requires-clause
meaning Clang should not generate the same mangled name for the two, separate (by separate requires-clauses) friend declarations.
MSVC is likely also wrong to the fail program (E) in the stage of overload resolution (with an ambiguity error), as e.g. foo(s1) should arguably only add candidates from S<1> to its candidate functions. Whether constraints checking can actually be applied for an argument that is Base& and not a particular specialization of S is another question, but the possible error should not be one of ambiguity but rather inability to fulfill the constraints of a candidate function.
US115: Hidden non-template friends need a requires-clause
US115 of P2103R0 (Core Language Changes for NB Comments at the February, 2020 (Prague) meeting) proposed updating the standard rules for non-template hidden friends such that (also) non-template friend (functions) should be allowed to use trailing requires-clauses:
US115. Hidden non-template friends need a requires-clause
Add the following after 3.20 [defns.signature]:
3.21 [defns.signature.friend]
signature
‹non-template friend function with trailing requires-clause› name, parameter-type-list (9.3.3.5 [dcl.fct]), enclosing class, and
trailing requires-clause (9.3 [dcl.decl])
Add the following after 3.21 [defns.signature.templ]:
3.23 [defns.signature.templ.friend]
signature
‹friend function template with constraint involving enclosing template parameters› name, parameter-type-list (9.3.3.5 [dcl.fct]),
return type, enclosing class, template-head, and trailing
requires-clause
Change 13.7.4 [temp.friend] paragraph 9 as follows:
A non-template friend declaration shall not have with a requires-clause shall be a definition. A friend function template
with a constraint that depends on a template parameter from an
enclosing template shall be a definition. Such a constrained friend
function or function template declaration does not declare the same
function or function template as a declaration in any other scope.
the majority of the change affection an expansion of
[temp.friend]/9.
US115 was recorded as issue 114 in cplusplus/nbballot:
US115 13.6.4 [temp.friend] Hidden non-template friends need a requires-clause
Hidden friends that are non-templates currently cannot have a requires-clause, but this functionality is important and used throughout Ranges.
Proposed change:
Change [temp.friend]/9 to refer only to those friend declarations that are not any kind of templated entity.
and was implemented in pull request #3782 to the standard draft, particularly as per the following commit:
NB US 115 (C++20 CD): Hidden non-template friends need a requires-clause
Added obviously-missing (if any) to the mention of a trailing
requires-clause in the definition of signature for a friend function
template.
I asked for clarification (given the different implementations of the GCC, Clang, MSVC) regarding the expanded rule of [temp.friend]/9 w.r.t. overloading hidden non-template friends solely based differences in trailing requires-clauses, with the answer that this should (likely) be legal, and that both GCC and Clang are wrong to reject example (E) in their respective manners (it should be an overload resolution ambiguity error:
Hubert Tong (hubert-reinterpretcast)
I think MSVC is correct here. With respect to the Clang behaviour, the description of the signature indicates that the mangling should be unique. With respect to the GCC behaviour, the "does not declare" wording is meant to say that the friends declared by each specialization is unique.
Consider the following example:
template <typename T>
class C
{
public:
friend void f() {}
friend void f(C<T>) {}
};
C<int> c;
void g(C<int>* p)
{
f();
f(*p);
}
Compiling with GCC 5.2 throws the following compile error:
no matching function for call to 'f()'
But the standard says in 14.6.5:
Friend classes or functions can be declared within a class template.
When a template is instantiated, the names of its friends are treated
as if the specialization had been explicitly declared at its point of instantiation.
Why does this fail to compile? In GCC 3.4, it passes.
f can only be found via argument-dependent name lookup (ADL). The second call compiles because the pointee of p, which is passed as an argument, is of type C<int> - this causes ADL to jump in and inspect otherwise invisible functions. In fact, the first overload of f can't be found at all, as there is no way of conveying an association to any specialization of C.
Just see the quote right after yours, [temp.inject]/2:
As with non-template classes, the names of namespace-scope friend functions of a class template specialization
are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.3). Such names
may be found under the rules for associated classes (3.4.2). 141
141) Friend declarations do not introduce new names into any scope, either when the template is declared or when it is
instantiated.
The call to f() is in no way associated with class C, so its friends are not used in the overload resolution.
In the other call, f(*p), the parameter is of class type and therefore the class and the namespace of the class are checked for possible candidates. That way the compiler will find both f functions and use overload resolution to select the proper one.
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.
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).
Consider this code:
template <int N>
struct X
{
friend void f(X *) {}
};
int main()
{
f((X<0> *)0); // Error?
}
compilers seem to heavily disagree. (MSVC08/10 says no, GCC<4.5 says yes, but 4.5 says no, sun 5.1 says yes, intel 11.1 says yes too but comeau says no (both are EDG)).
According to "C++ Templates - The complete guide":
... it is assumed that a call
involving a lookup for friends in
associated classes actually causes the
class to be instantiated ... Although
this was clearly intended by those who
wrote the C++ standard, it is not
clearly spelled out in the standard.
I couldn't find the relevant section in the standard. Any reference?
Consider this variation:
template <int N>
struct X
{
template <int M>
friend void f(X<M> *) {}
};
template <>
struct X<0>
{
};
int main()
{
X<1>();
f((X<0> *)0); // Error?
}
The key issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.
What's your take on that?
The Standard says at 14.7.1/4
A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);
Note that Vandervoorde made an issue report here, and the committee found
The standard already specifies that this creates a point of instantiation.
For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).
If T is a template-id, its associated namespaces and classes are the namespace in which the template is
defined; [... lots of noise ...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.
So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are
Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup
There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.