Friend template function in-class definition - c++

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.

Related

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 function name visible in class template

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.

Namespace causes sub-optimal template overload resolution

This is very similar to this question, but I'm not sure the answer there is entirely applicable to the minimal code I've put together that demonstrates the issue. (My code does not use trailing-return types, and there are some other differences as well.) Additionally, the issue of whether MSVC's behavior is legal doesn't seem to be addressed.
In short, I'm seeing the compiler select a generic function template instantiation rather than a more-specific overload when the function template is inside a namespace.
Consider the following set of namespace and class definitions:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff; // No effect.
void doStuff(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
... and the following use-cases:
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Triggers static assert
util.doStuffWithObjectRef(scoped_foo); // Triggers static assert
}
If the entire DoStuffUtilNamespace is eliminated and all its members are moved to global scope, this compiles fine with G++ and Clang++.
With the namespace, doStuff is of course a dependent name. According to the top-voted answer on the similar question, the standard says:
In resolving dependent names, names from the following sources are considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
This seems a little odd to me; I don't understand why the first bullet point would specify that the declarations must be visible at the point of definition of the template rather than at the point of instantiation, since the second bullet point explicitly specifies that some declarations visible only at the point of instantiation are allowed. (If someone would like to offer a rationale, I'd appreciate it, but that's not my question because it's my understanding that questions of the form "why did the standards committee decide X" are off topic.)
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
But what exactly does the standard mean by "namespaces associated with the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together with the explicit scoping of the scoped_foo instance type within the namespace, trigger argument-dependent lookup, and shouldn't this look-up find the non-asserting definition of doStuff()?
Also, the entire code is compiled without error using clang++ -ftemplate-delayed-parsing, which emulates MSVC's template-parsing behavior. This seems preferable, at least in this particular case, because the ability to add new declarations to a namespace at any time is one of the primary appeals of namespaces. But, as noted above, it doesn't quite seem to follow the letter of the law, according to the standard. Is it permissible, or is it an instance of non-conformance?
EDIT:: As pointed out by KIIV, there is a workaround; the code compiles if template specialization is used instead of overloading. I would still like to know the answers to my questions about the standard.
With the namespace, doStuff is of course a dependent name.
You are starting from the wrong premise. There is no ADL for a qualified call like DoStuffUtilNamespace::doStuff(ref). [basic.lookup.argdep]/p1, emphasis mine:
When the postfix-expression in a function call (5.2.2) is an
unqualified-id, other namespaces not considered during the usual
unqualified lookup (3.4.1) may be searched, and in those namespaces,
namespace-scope friend function or function template declarations
(11.3) not otherwise visible may be found.
DoStuffUtilNamespace::doStuff is a qualified-id, not an unqualified-id. ADL doesn't apply.
For this reason, DoStuffUtilNamespace::doStuff is also not a dependent name. [temp.dep]/p1:
In an expression of the form:
postfix-expression ( expression-listopt)
where the postfix-expression is an unqualified-id, the
unqualified-id denotes a dependent name if [...]. If an operand of an operator is a type-dependent expression, the operator also denotes
a dependent name. Such names are unbound and are looked up at the
point of the template instantiation (14.6.4.1) in both the context of
the template definition and the context of the point of instantiation
(The italicization of dependent name indicate that this paragraph is defining the term.)
Instead, per [temp.nondep]/p1:
Non-dependent names used in a template definition are found using the
usual name lookup and bound at the point they are used.
which doesn't find your later overload declaration.
Specialization works because it's still the same function template declaration that's used; you just supplied a different implementation than the default one.
But what exactly does the standard mean by "namespaces associated with
the types of the function arguments"? Shouldn't the using ::MyClassThatCanDoStuff declaration, together
with the explicit scoping of the scoped_foo instance type within the
namespace, trigger argument-dependent lookup
No. using-declarations do not affect ADL. [basic.lookup.argdep]/p2, emphasis mine:
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 a fundamental type, [...]
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
innermost enclosing namespaces of its associated classes. Furthermore,
if T is a class template specialization, its associated namespaces and
classes also include: the namespaces and classes associated with the
types of the template arguments provided for template type parameters
(excluding template template parameters); the namespaces of which any
template template arguments are members; and the classes of which any
member templates used as template template arguments are members. [
Note: Non-type template arguments do not contribute to the set of associated namespaces. —end note ]
[...]
With template specialization I can get it work:
namespace DoStuffUtilNamespace
{
template<typename UNKNOWN>
void doStuff(UNKNOWN& foo)
{
static_assert(sizeof(UNKNOWN) == -1, "CANNOT USE DEFAULT INSTANTIATION!");
}
}
class UtilForDoingStuff
{
public:
template <typename UNKNOWN>
void doStuffWithObjectRef(UNKNOWN& ref)
{
DoStuffUtilNamespace::doStuff(ref);
}
};
class MyClassThatCanDoStuff { };
namespace DoStuffUtilNamespace
{
using ::MyClassThatCanDoStuff;
template <> void doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo) { /* No assertion! */ }
}
int main()
{
MyClassThatCanDoStuff foo;
DoStuffUtilNamespace::MyClassThatCanDoStuff scoped_foo;
UtilForDoingStuff util;
DoStuffUtilNamespace::doStuff(foo); // Compiles
DoStuffUtilNamespace::doStuff(scoped_foo); // Compiles
util.doStuffWithObjectRef(foo); // Compiles
util.doStuffWithObjectRef(scoped_foo); // Compiles
}
Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
Example with the following code which prints B::foo Demo
namespace A
{
template <typename T>
void foo(const T&) {std::cout << "A::foo" << std::endl;}
template <typename T>
void bar(const T& t) {
foo(t); // thank to ADL, it will also look at B::foo for B::S.
}
}
namespace B
{
struct S {};
void foo(const S&) {std::cout << "B::foo" << std::endl;}
}
int main()
{
B::S s;
A::bar(s);
}
So when calling ?::foo(const B::S&), the second bullet point adds B::foo to the list of overloads.
why template-specialization works in this case
There is only one function:
template<>
void DoStuffUtilNamespace::doStuff<MyClassThatCanDoStuff>(MyClassThatCanDoStuff& foo);
even if it is defined later.
Note that the fact that there is a specialization should be known in the translation unit, else the program is ill formed (doesn't respect ODR).
while overloading doesn't.
You think:
So I think that explains why util.doStuffWithObjectRef(foo); triggers the static assertion: doStuff(MyClassThatCanDoStuff&) hasn't been declared at the point of definition of UtilForDoingStuff::doStuffWithObjectRef<UNKNOWN>(UNKNOWN&). And indeed moving the class UtilForDoingStuff definition after the doStuff overload has been defined seems to fix the issue.
Exactly.

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

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.

I need some clarification regarding this example on Stroustrup's new book about ADL

I reproduce below the argument-dependent lookup (ADL) example given in pages 396 and 397 of Stroustrup book (4th edition):
namespace N {
struct S { int i; };
void f(S);
void g(S);
void h(int);
};
struct Base {
void f(N::S);
};
struct D : Base {
void mf(N::S);
void g(N::S x)
{
f(x); // call Base::f()
mf(x); // call D::mf()
h(1); // error: no h(int) available
}
};
What the comments say above is correct (I've tested it), but that doesn't seem to agree with what the author says in the next paragraph:
In the standard, the rules for argument-dependent lookup are phrased
in terms of associated namespaces (iso §3.4.2). Basically:
If an argument is a class member , the associated namespaces are the class itself (including its base classes) and the class's
enclosing namespaces.
If an argument is a member of a namespace, the associated namespaces are the enclosing namespaces.
If an argument is a built-in type, there are no associated namespaces.
In the example, x, which has type N::S is not a member of class D, nor of its base Base. But it's a member of namespace N. According to the second bullet above, the function N::f(S) should be the one called, instead of Base::f().
The result above also doesn't seem to agree with the second bullet in paragraph 3.4.2p2 in the Standard, which says:
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 of which its associated classes are members. Furthermore,
if T is a class template specialization, its associated namespaces and
classes also include: the namespaces and classes associated with the
types of the template arguments provided for template type parameters
(excluding template template parameters); the namespaces of which any
template template arguments are members; and the classes of which any
member templates used as template template arguments are members.
3.4.2/3 Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent
lookup (defined as follows). If X contains
a declaration of a class member, or
a block-scope function declaration that is not a using-declaration, or
a declaration that is neither a function or a function template
then Y is empty. Otherwise...
So basically, ADL doesn't kick in when the ordinary lookup finds a member function or local (block-scope) function declaration (or something that's not a function). It does kick in when the ordinary lookup finds a stand-alone namespace-scope function, or when it finds nothing at all.