What are the rules for using qualified names in friend declarations? - c++

The following code produces a compile error (on a recent version of gcc at least):
namespace a {
class X { friend void ::foo(); };
}
The error is:
'void foo()' should have been declared inside '::'
If we remove :: from the declaration, according to the standard, foo will be introduced into the namespace a (although it won't be visible). Predeclaring foo inside of a is not required.
My question is, given the above, why is predeclaring within the global namespace a requirement? Why doesn't the name foo become a member of the global namespace? I couldn't find any paragraph in the standard that would explicitly forbid that either, so I'm curious to know.

The paragraph you're looking for is [dcl.meaning] (8.3 (1) in C++11):
(...) A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable of a namespace outside of its namespace, or the definition of an explicit specialization outside of its namespace, or the declaration of a friend function that is a member of another class or namespace. 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 (or, in the case of a namespace, of an element of the inline namespace set of that namespace).
(emphasis mine) What this means is that you cannot write
namespace a { }
void a::foo() { }
unless a::foo is already declared with an unqualified declarator inside the namespace. And since there is no exception for friends, you cannot do this for friends either.
A footnote in [namespace.memdef] (7.3.1.2 (3) in C++11) mentions this even more explicitly for the special case of friends:
(...) If a friend declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. (...)
95) This implies that the name of the class or function is unqualified.

Related

using namespace for function-member definition

I have the following class definition in .h file:
namespace N {
struct S {
S(); // no definition for member here
};
}
And I would like to write definition for class constructor (member in general) in .cpp file. I consider the following two cases:
namespace N {
S::S() { /* definition */ }
}
using namespace N;
S::S() { /* definition */ }
I'm slightly confused why the second is working at all, because never saw this way definition until today. Why the second is working? Some citing from the Standard would be appreciated.
What are the nuances of using one approach instead of the other? Should I prefer the first or the second form?
The reason (2) works is because of these two:
[class.mfct]/4
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the ​::​ operator.
[namespace.udir]/2 (emphasis mine)
A using-directive specifies that the names in the nominated namespace
can be used in the scope in which the using-directive appears after
the using-directive. During unqualified name lookup, the names appear
as if they were declared in the nearest enclosing namespace which
contains both the using-directive and the nominated namespace. [ Note:
In this context, “contains” means “contains directly or indirectly”.
 — end note ]
The directive simply lets you name S for the :: operator as if you were inside the N namespace (as you are in (1)). But I wouldn't do that. Scoping is good. Definitions should be scoped too.
In this particular example you have declared only one structure in the namespace and defined the function in a separate .cpp file, so it doesn't matter if you use 1 or 2.
Had you declared any other identifiers in the namespace, then 1 should be preferred over 2 as the using declaration kind of defeats the purpose of having a namespace.

What is the fully qualified name of a friend function defined inside of a class?

What is the fully qualified name of a friend function defined inside of a class?
I recently saw an example analogous to the following. What is the fully qualified name of val() below?
#include <iostream>
namespace foo {
class A {
int x;
public:
A(int x = 0) : x(x) { }
friend int val(const A &a) { return a.x; }
};
}
int main() {
foo::A a(42);
// val() found using ADL:
std::cout << val(a) << std::endl;
// foo::val(a); // error: 'val' is not a member of 'foo'
// foo::A::val(a); // error: 'val' is not a member of 'foo::A'
return 0;
}
Is argument-dependent lookup the only way val() can be found?
Admittedly, this does not stem from a practical problem. I am simply looking to gain a better understanding.
Is argument-dependent lookup the only way val() can be found?
Yes, it is the only way. To quote the holy standard at [namespace.memdef]/3:
If a friend declaration in a non-local class first declares a class,
function, class template or function template the friend is a member
of the innermost enclosing namespace. The friend declaration does not
by itself make the name visible to unqualified lookup or qualified lookup.
So while val is a member of foo, it's not visible to lookup from the friend declaration alone. An out of class definition (which is also a declaration) is required to make it visible. For an inline definition (and no out-of-class declaration) it means ADL is the only way to call the function.
As an added bonus, C++ did once have a concept of "friend name injection". That however has been removed, and the rules for ADL adjusted as a replacement. A more detailed overview can be found in WG21 paper N0777 (pdf).
C++ Standard [7.3.1.2/3 (of ISO/IEC 14882:2011)]:
Every name first declared in a namespace is a member of that
namespace. If a friend declaration in a non-local 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 (3.4.1) or by qualified lookup (3.4.3) until a
matching declaration is provided in that namespace scope (either
before or after the class definition granting friendship). If a friend
function is called, its name may be found by the name lookup that
considers functions from namespaces and classes associated with the
types of the function arguments (3.4.2). If the name in a friend
declaration is neither qualified nor a template-id and the declaration
is a function or an elaborated-type-specifier, the lookup to determine
whether the entity has been previously declared shall not consider any
scopes outside the innermost enclosing namespace.

Friend template function in-class definition

I have no idea, why gcc compiles this code
#include <type_traits>
template<class Type, class ValueT>
class ImplAdd
{
template<typename T>
friend typename std::enable_if<std::is_same<T, ValueT>::value, Type>::type
operator+(T, T)
{
return Type{};
}
};
enum class FooValueT { ONE, ZERO };
class Foo : ImplAdd<Foo, FooValueT>
{
public:
Foo() {}
Foo(FooValueT) {}
};
struct A {};
int main()
{
Foo f = FooValueT::ONE + FooValueT::ZERO;
}
clang and msvc doesn't compile, and it seems to me, that they are right. Is it bug in GCC compiler? Version of gcc is 4.8.2.
Question is caused by my answer in question: In-class friend operator doesn't seem to participate in overload resolution, there is quote from standard in answer, that points, that such definition should be in class-scope, and if function is not template - gcc reject this code, that is right. Thanks for answers, and quotes from standard, that proves, that gcc is right (or not) are very appreciated.
I would say GCC accepts this incorrectly. Quoting C++11, emphasis mine:
Namespace membership, 7.3.1.2/3
Every name first declared in a namespace is a member of that namespace. 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 (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition
granting friendship). If a friend function is called, its name may be found by the name lookup that considers
functions from namespaces and classes associated with the types of the function arguments (3.4.2). ...
Argument-dependent lookup, 3.4.2/2:
For each argument type T in the function call, there is a set of zero or more associated namespaces and a
set of zero or more associated classes to be considered. The sets of namespaces and classes is determined
entirely by the types of the function arguments (and the namespace of any template template argument).
Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of
namespaces and classes are determined in the following way:
...
If T is an enumeration type, its associated namespace is the namespace in which it is defined. If it is
class member, its associated class is the member’s class; else it has no associated class.
...
3.4.2/4:
When considering an associated namespace, the lookup is the same as the lookup performed when the
associated namespace is used as a qualifier (3.4.3.2) except that:
...
Any namespace-scope friend functions or friend function templates declared in associated classes are
visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3).
...
Based on the above, I reason that FooValueT (the type of FooValueT::ONE and FooValueT::TWO) has :: as an associated namespace, but has no associated classes (since it's an enumeration). Therefore, friend functions defined in class template ImplAdd should not be considered during ADL.

VS 2013 - IntelliSense reporting false positives?

I'm working on a C++ project where, among other things, I have an interface with a few pure virtual methods. The problem arises when I try to implement that interface - IntelliSense doesn't seem to agree with the derived class's method declaration. An example of such a method:
// DLL_EXPORT -> #define DLL_EXPORT __declspec(dllexport)
// IPlayer
DLL_EXPORT virtual const Grid& GetGrid() const = 0;
Declaration in one of the derived classes:
// Human : IPlayer
DLL_EXPORT const Grid& IPlayer::GetGrid() const;
The error it keeps nagging me with - "IntelliSense: declaration must correspond to a pure virtual member function in the indicated base class". The code compiles without errors and runs fine, all of the "problematic" methods do their jobs as expected during run time. What is worth mentioning is that the error disappears if I remove the IPlayer:: scope qualifier in the derived class. I wanted to keep it there for readability reasons. Also, I am NOT proficient in C++ so there could be something obviously wrong with the example I've provided.
Minimized example:
struct C { virtual void f() = 0; };
struct D : C { void C::f() { } };
This doesn't compile in any version of g++ or clang that I tested. Intellisense in VS2013 uses the EDG frontend, and to quote Jonathan Wakely, "If GCC, Clang and EDG all agree and MSVC disagrees that usually means MSVC is wrong."
To make things more interesting, the relevant paragraphs in the standard actually changed between C++11 and C++14.
In C++11, this is flat-out illegal (N3337 §8.3 [dcl.meaning]/p1):
A declarator-id shall not be qualified except for the definition of a
member function (9.3) or static data member (9.4) outside of its
class, the definition or explicit instantiation of a function or
variable member of a namespace outside of its namespace, or the
definition of an explicit specialization outside of its namespace, or
the declaration of a friend function that is a member of another class
or namespace (11.3).
This sentence was removed in C++14 as a result of CWG issue 482. The proposed resolution for that issue has the following note:
[Drafting note: The omission of “outside of its class” here does not
give permission for redeclaration of class members; that is still
prohibited by 9.2 [class.mem] paragraph 1. The removal of the
enumeration of the kinds of declarations in which a qualified-id can
appear does allow a typedef declaration to use a qualified-id, which
was not permitted before; if that is undesirable, the prohibition can
be reinstated here.]
In C++14, the only applicable rule in §8.3 [dcl.meaning]/p1 is now (quoting N3936):
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 (or, in the case of a namespace, of an element of the
inline namespace set of that namespace (7.3.1)) or to a specialization
thereof; the member shall not merely 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.
The relevant part of §9.2 [class.mem]/p1 is:
Except when used to declare friends (11.3) or to introduce the name of
a member of a base class into a derived class (7.3.3),
member-declarations declare members of the class, and each such
member-declaration shall declare at least one member name of the
class. A member shall not be declared twice in the
member-specification, except that a nested class or member class
template can be declared and then later defined, and except that an
enumeration can be introduced with an opaque-enum-declaration and
later redeclared with an enum-specifier.
Since a using-declaration "to introduce a member of a base class into a derived class" is made an explicit exception, it appears that base class members are not considered members for the purposes of the rule that "member-declarations declare members of the class, and each such member-declaration shall declare at least one member name of the class". If so, then it follows that using a qualified-id like void C::f() { } in a member-declaration is also not allowed in C++14, since that qualified-id refers to a member of C, not a member of D.

Namespace member definition

namespace M{
void f();
void M::f(){}
}
int main(){}
The above code gives error like so:
"ComeauTest.c", line 3: error:
qualified name is not allowed in
namespace member
declaration
void M::f(){}
And
G++ also gives error.
But
VS2010 compiles fine.
My questions are:
a) What is the expected behavior?
b) $7.3.1.2 does not seem to talk about this restriction. Which portion of the Standard guides the behavior of such code?
Which portion of the Standard guides the behavior of such code?
C++03 Section $8.3 says
A declarator-id shall not be qualified except for the definition of a member function (9.3) or static data member (9.4) out-side of its class, the definition or explicit instantiation of a function or variable member of a namespace out-side of its namespace, or the definition of a previously declared explicit specialization outside of its name-space, or the declaration of a friend function that is a member of another class or namespace (11.4).
So your code is ill-formed.
However in discussing issue 548 the CWG agreed that the prohibition of qualified declarators inside their namespace should be lifted1.
1 : Active Issue 482
7.3.1.2-2 talks specifically about this:
Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.
M::f is considered a outside of namespace definition.