Here is a little experiment with return type deduction for in-class friend functions (using Clang 3.4 SVN and g++ 4.8.1 with std=c++1y
in both cases) that is not documented in the linked working paper
#include <iostream> struct A { int a_; friend auto operator==(A const& L, A const& R) { return L.a_ == R.a_; // a_ is of type int, so should return bool } }; template<class T> struct B { int b_; friend auto operator==(B const& L, B const& R) { return L.b_ == R.b_; // b_ is of type int, so should return bool } }; using BI = B<int>; int main() { std::cout << (A{1} == A{2}) << "\n"; // OK for Clang, ERROR for g++ std::cout << (BI{1} == BI{2}) << "\n"; // ERROR for both Clang and g++ }
Live Example.
Question: is automatic return type deduction for in-class friend functions supported in C++14?
As we can see above, the friend function should be declared inside the class whose private and protected members are to be accessed. Let's breakdown the syntax: friend is a keyword to denote that this function is a friend function. returnType is the function's return type.
Friend functions can be defined (given a function body) inside class declarations. These functions are inline functions. Like member inline functions, they behave as though they were defined immediately after all class members have been seen, but before the class scope is closed (at the end of the class declaration).
A friend function can be friendly to 2 or more classes. The friend function does not belong to any class, so it can be used to access private data of two or more classes as in the following example. The friend functions can serve, for example, to conduct operations between two different classes.
With respect to the other answers: We're dealing explicitly with n3638 here, and how it's incorporated in the recent drafts of C++1y.
I'm using 9514cc28 from the commitee's github repository, which incorporates some (minor) fixes/changes to n3638 already.
n3638 allows explicitly:
struct A { auto f(); // forward declaration }; auto A::f() { return 42; }
And, as we can infer from [dcl.spec.auto], where this feature is specified, even the following will be legal:
struct A { auto f(); // forward declaration }; A x; auto A::f() { return 42; } int main() { x.f(); }
(but more on this later)
This is fundamentally different from any trailing-return-type or dependent name lookup, as auto f();
is a preliminary declaration, similar to struct A;
. It needs to be completed later on, before it is used (before the return type is required).
Additionally, the problems in the OP are related to internal compiler errors. The recent clang++3.4 trunk 192325 Debug+Asserts build fails to compile as an assertion fails while parsing the line return L.b_ == R.b_;
. I have not checked with a recent version of g++ as of now.
Is the OP's example legal wrt to a n3638?
This is a bit tricky IMO. (I'm always referring to 9514cc28 in this section.)
[dcl.spec.auto]
6 A program that uses
auto
ordecltype(auto)
in a context not explicitly allowed in this section is ill-formed.2 The placeholder type can appear with a function declarator in the decl-specifier-seq, type-specifier-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid.
/5 also defines some contexts, but they're irrelevant here.
Therefore, auto func()
and auto operator@(..)
are generally allowed (this follows from the composition of a function declaration as T D
, where T
is of the form decl-specifier-seq, and auto
is a type-specifier).
[dcl.spec.auto]/1 says
The
auto
anddecltype(auto)
type-specifiers designate a placeholder type that will be replaced later, either by deduction from an initializer or by explicit specification with a trailing-return-type.
and /2
If the declared return type of the function contains a placeholder type, the return type of the function is deduced from
return
statements in the body of the function, if any.
Although it doesn't explicitly allow a declaration like auto f();
for a function (that is, a declaration without definition), it is clear from n3638 and [dcl.spec.auto]/11 that it is intended to be allowed, and not explicitly forbidden.
So far, the example
struct A { int a_; friend auto operator==(A const& L, A const& R); } auto operator==(A const& L, A const& R) { return L.a_ == R.a_; }
should be well-formed. The interesting part now is the definition of the friend function inside the definition of A
, that is
struct A { int a_; friend auto operator==(A const& L, A const& R) { return L.a_ == R.a_; } // allowed? }
In my opinion, it is allowed. To support this, I'll cite name lookup. The name lookup inside the definition of functions defined in a friend function declaration follows the name lookup of member functions as per [basic.lookup.unqual]/9. /8 of the same section specifies unqualified lookup for names used inside member function bodies. One of the ways a name can be declared to be used is that it "shall be a member of class X
or be a member of a base class of X
(10.2)". This allows the widely known
struct X { void foo() { m = 42; } int m; };
Note how m
isn't declared before its use in foo
, but it's a member of X
.
From this, I conclude that even
struct X { auto foo() { return m; } int m; }
is allowed. This is supported by clang++3.4 trunk 192325. Name lookup requires to interpret this function only after the struct
has been completed, also consider:
struct X { auto foo() { return X(); } X() = delete; };
Similarly, the body of friend functions defined inside a class can only be interpreted once the class is complete.
Specifically, what about friend auto some_function(B const& L) { return L.b_; }
?
First, the injected-class-name B
is equivalent to B<T>
, see [temp.local]/1. It refers to the current instantiation ([temp.dep.type]/1).
The id-expression L.b_
refers to a member of the current instantiation (/4). It is also a dependent member of the current instantiation -- this is an addition made after C++11, see DR1471, and I don't know what to think about it: [temp.dep.expr]/5 states this id-expression is not type-dependent, and as far as I see [temp.dep.constexpr] doesn't say it's value-dependent.
If the name in L.b_
was not dependent, name lookup would follow the "usual name lookup" rules per [temp.nondep]. Else, this'll be fun (dependent name lookup is not very well specified), but considering that
template<class T> struct A { int foo() { return m; } int m; };
is accepted by most compilers as well, I think the version with auto
should be valid, too.
There's also a section about friends of templates in [temp.friend], but IMO it doesn't shed light on the name lookup here.
Also see this highly relevant discussion in the isocpp-forum.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With