Overloaded function name lookup - c++

There are 3 examples:
I.
int foo(int i){ return 0; }
namespace A
{
int foo();
int a = foo(5);//Error: too many argument to function int a::foo()
}
II.
namespace A
{
int foo(int i){ return 0; }
int foo(){ return 1; }
int a = foo(5);//OK, Call A::foo(int)
}
III
namespace A
{
int foo(){ return 1; }
int foo(int i){ return 0; }
int a = foo(5);//OK, Call A::foo(int)
}
What exactly rules used to determine the set of candidate functon? I thought that (3.4.1/1)
name lookup ends as soon as a declaration is found for the name.
It is unclear what declaration (int foo(int) or int foo()) will be found first in the cases II and III?

From §13-1 Overloading,
When two or more different declarations are specified for a single name in the same scope, that name is said
to be overloaded. By extension, two declarations in the same scope that declare the same name but with
different types are called overloaded declarations. Only function and function template declarations can be
overloaded; variable and type declarations cannot be overloaded.
Since you have overloaded function declarations in the same namespace, unqualified name lookup finds matches the set of functions and stops. (I admit the standardese seem a bit incorrect here since it says "as soon as a declaration is found for the name".)
So for II and III, unqualified name lookup finds the same set of overloaded functions.
Extending III a bit further,
int foo(int i) { return 42; }
namespace A {
int foo() { return 1; }
int foo(int i) { return 0; }
int a = foo(5); // OK, Call A::foo(int)
}
Now, it may seem as ::foo(int) and A::foo(int) might be ambiguous but it's not because unqualified name lookup stops after finding A::foo() and A::foo(int). Then it's up to overload resolution to pick the best viable function.

Function overloading only works if the functions are in the same namespace. That is, the name is looked up first by namespace, then by the function signature. In case I, there is a function named foo inside of the A namespace, so it tries to call that, but there is no definition of foo in that namespace which accepts an integer parameter.
In any case, you can call the global foo function as follows:
int a = ::foo(5);
The double colon, with no namespace prefix accesses the global namespace.

Related

Scope while initializing static variables

So there is a question I came across
int f() {
return 5;
}
struct A{
static int sX;
static int f() {
return 1;
}
};
int A::sX = f(); // (1)
This complies fine. I wanted to understand why (1) ends up having a
call A::f()
in its compiled code. I understand there is some scope rule being invoked here but would like to know the exact rule. I'd expected it to invoke the global f(). Why doesn't the (unqualified?)name lookup of f yield the global function?
P.S. I'd looked up ADL but since f() doesn't accept any arguments, would ADL kick in?
Edit: I think I found the answer to my question. Check this link under unqualified name lookup which states:
For a name used in the definition of a namespace-member variable
outside the namespace, lookup proceeds the same way as for a name used
inside the namespace:
namespace X {
extern int x; // declaration, not definition
int n = 1; // found 1st
};
int n = 2; // found 2nd.
int X::x = n; // finds X::n, sets X::x to 1

C++ name lookup - example from the standard

I need an explanation on this example from standard [basic.lookup.unqual]/3:
typedef int f;
namespace N {
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
}
};
}
I would argue that void N::f(A &) is closer than int(a) because it does not involve the type-cast operator. I cannot however be sure because the standard contains only one instance of "type cast".
By the way, compiling that code fails in MSVC2015 (but it works in clang and g++).
Error C2440 'initializing': cannot convert from 'void' to 'int'
UPDATE
Addressing some of the comments.
Type casting is formally known as "type conversions" and they are covered in (12.3) (thanks jefffrey).
What I am looking for is a description of the syntax parsing. In particular, why postfix-expression ( expression-list opt ) is trampled over by simple-type-specifier ( expression-list opt ). Since according to (5.2), both of those expression are evaluated left-to-right. Hence, out of the two candidates to be before the (a), ::N::f should be closer than ::f when evaluating expressions in ::N::A::g.
"Type casting" has nothing to do with this scenario. The rules for argument-dependent lookup include, from [basic.lookup.argdep]:
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
(3.1) — a declaration of a class member, or
(3.2) — a block-scope function declaration that is not a using-declaration, or
(3.3) — a declaration that is neither a function or a function template
then Y is empty. Otherwise Y is the set of declarations found in the namespaces associated with the argument types as described below. The set of declarations found by the lookup of the name is the union of
X and Y.
The lookup set produced by unqualified lookup for f is:
typedef int f;
That declaration is neither a function nor a function template, therefore Y is empty. We do not consider the friend function f, since it is not visible to unqualified lookup.
There are a few things going on here. As the note containing the example says (3.4/3):
For purposes of determining (during parsing) whether an expression is a postfix-expression for a function call, the usual name lookup rules apply. The rules in 3.4.2 have no effect on the syntactic interpretation of an expression.
So first we need to know whether f is a simple-type-specifier or a postfix-expression, using name lookup rules that don't include section 3.4.2. And under these rules, the function N::f is not visible.
7.3.1.2/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 (3.4.1) or qualified lookup (3.4.3).
Therefore the unqualified lookup does not see any declaration of N::f at all, and finds only ::f, which is a typename. So the syntax is simple-type-specifier ( expression-list opt ) and not postfix-expression ( expression-list opt ), and argument-dependent lookup (3.4.2) does not apply.
( If the unqualified lookup had found a function name, 3.4.2 would apply and would be able to include N::f in the candidate list despite the lack of declaration. If N::f had a previous declaration other than the friend declaration, it would have won the unqualified lookup. )
The statements around the quote are actually quite clear on why the example does not call the function f:
Because the expression is not a function call, the argument-dependent name lookup (3.4.2) does not apply and the friend function f is not found.
The actual question is why the argument-dependent look-up is not applies. It seems 5.2.3 [expr.type.conv] paragraph 1 applies:
A simple-type-specifier (7.1.6.2) or typename-specifier (14.6) followed by a parenthesized expression-list constructs a value of the specified type given the expression list.
Clearly, f is a simple-type-specifier: the typedef int f; arranges for that to be the case. Remove this typedef and f isn't a simple-type-specifier anymore resulting in N::A::f being found.
According to [class.conv]/1 (emphasis mine):
Type conversions of class objects can be specified by constructors and by conversion functions.
Thus, both ::N::f and ::N::A::operator int() are functions. However, [namespace.memdef]/3 specifies (emphasis mine):
If a friend declaration in a non-local class first declares a class, function, class template or function template 97 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3).
Since ::N::f is out of the picture while looking up for names, the closest is ::f which then becomes ::N::A::operator int().
The following code should clarify things. Because it fails to compile (in clang), it shows that ::N::f has preference over ::f when ::N::f is actually in the list of available names.
#include <boost/type_index.hpp>
#include <iostream>
typedef int f;
namespace N {
struct A;
void f( A & )
{
std::cout << "::N::f\n";
}
struct A {
friend void f(A &);
operator int() { std::cout << "Yes, I am a function\n"; return 5; }
void g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
std::cout << boost::typeindex::type_id_with_cvr<decltype(f(a))>().pretty_name() << '\n';
std::cout << i;
}
};
}
int main()
{
N::A a;
a.g( a );
}
Further explanation
The part
void f( A & )
{
std::cout << "::N::f\n";
}
is both the declaration (and the definition) of ::N::f. That is, it introduces the name ::N::f in the list of names contained in ::N. When evaluating the f in int i = f(a), we look in the list available names and we find ::N::f before ::f. Hence f(a) is type void and the code above fails to compile with the message "cannot initialize a type int with a type void". That is, int i = f(a) calls ::N::f when ::N::f is available even in the presence of ::N::A::operator int.
On the other hand, if we remove the ::N::f definition part, the name ::N::f exists only as introduced by the friend declaration. Since such a name cannot be the result of a lookup, then the f in f(a) is the next available, which is the global typedef ::f. Now that we know that the f in f(a) is int, we can call the function ::N::A::operator int.
Standard (n4296) says as 11.3 §1 (Member access control / Friends) A class specifies its friends, if any, by way of friend declarations. Such declarations give
special access rights to the friends, but they do not make the nominated friends members of the befriending
class.
And at 7.3.1.2 (Namespace member definitions) §3 The friend declaration does not by
itself make the name visible to unqualified lookup or qualified lookup
.
I slightly modified your example to make it simpler to see what actually happens:
any try to declare f outside N (meaning at top level scope) gives an error redefinition of 'f' as different kind of symbol, be it before of after the namespace N block
typedef int f;
namespace N {
struct A {
friend int f(A &);
operator int();
int g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
return i;
}
int i;
A(int i): i(i) {};
};
}
int f(N::A& a) { // Error here
return 2*a.i;
}
N::A::operator int() {
return this->i;
}
if f is declared (in namespace N) after int i = f(a) f is taken as the int conversion:
#include <iostream>
typedef int f;
namespace N {
struct A {
friend int f(A &);
operator int();
int g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
return i;
}
int i;
A(int i): i(i) {};
};
int f(A& a) {
return 2*a.i;
}
}
N::A::operator int() {
return this->i;
}
int main() {
N::A a(2);
std::cout << a.g(a) << std::endl;
return 0;
}
outputs 2
if f is declared before int i = f(a) the function declaration inside the namespace has precedence over int conversion:
#include <iostream>
typedef int f;
namespace N {
int f(struct A&); // <= simple DECLARATION here
struct A {
friend int f(A &);
operator int();
int g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
return i;
}
int i;
A(int i): i(i) {};
};
int f(A& a) {
return 2*a.i;
}
}
N::A::operator int() {
return this->i;
}
int main() {
N::A a(2);
std::cout << a.g(a) << std::endl;
return 0;
}
outputs 4
TL/DR : The example on the standard assumes that there is no declaration of the function f before int i = f(a);. As a friend declaration in a class or in a namespace does not make the name visible to unqualified lookup or qualified lookup, the only declaration that is visible at that time is typedef int f;. So f is taken as the typedef.
But if there is a declaration for the function f in the namespace, it will take precedence over the typedef, because in N scope it hides the top level declaration.

Overloading vs Hiding c++

a theoretical question - can an inner definition function overload an outer definition?
For example:
int foo(){
class x{
public:
int foo() { return 1; }
int bar() { return foo(); }
}
return 0;
}
The inner foo hides the outer one in class x. Can someone give an example of an inner function overloading an outer function, and not hiding it?
Thank you!
I think you mean whether a member function can overload a namespace scope function.
The word overload here essentially means that two or more functions with different signatures (number of arguments and/or their types) are accessible visible to name lookup, and have the same name.
I don't think it's possible to overload so that the same unqualified name can stand for either member function or namespace scope function depending on arguments. E.g.,
#include <cmath> // std::sin
struct S
{
void sin() const { cout << "By Odin!" << endl; }
void foo()
{
using std::sin;
sin( 3.14 ); // OK.
//sin() !Will not find the member func.
}
};
Conversely, without the using declaration the member function can be called unqualified, but not the namespace scope function.
Function overloading means that you have two functions with the same name, but different parameters. You could have a function foo(int a) and then define a function foo(double a) without hiding the other one.

In C++ template function, why does dependent function call give "not declared" error?

Inside a C++ template function foo(), a call to ::bar(TT*) gives the following error under gcc 4.4.3:
g++ -o hello.o -c -g hello.cpp
hello.cpp: In function 'void foo(std::vector<TT*, std::allocator<TT*> >&)':
hello.cpp:8: error: '::bar' has not been declared
Here's the offending code:
// hello.cpp
#include <vector>
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
};
void bar(Blah *&)
{
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
C++ distinguishes between symbols that are dependent on the template parameter (TT, here) and those symbols that are independent and can be evaluated immediately.
Clearly, the compiler thinks my ::bar(TT*) call is independent and tries to resolve it immediately. Just as clearly, that function call is dependent on TT because the function call takes a parameter of type TT*, so the compiler should wait until the foo(vec) instantiation to resolve ::bar(TT*).
Is this a gcc bug or am I missing something subtle about C++ templates?
EDIT: here's a slightly more complicated example with two versions of ::bar() to clarify that declaration order is not the issue with my problem. When parsing the template, the compiler has no way of knowing if main() down below is going to instantiate the template function with TT=Blah or with TT=Argh. Therefore the compiler should not be giving an error until line 35 line 28 at the earliest (if ever). But the error is given for line 8 line 16.
EDIT #2: improved this example.
EDIT #3: added corrections to this example to make it work as desired. The bar(tt) now correctly refers to bar(Blah*). Rationale given below. (Thanks everyone).
// hello.cpp
#include <vector>
class XX {};
void bar(XX*) {}
class CC {
public:
void bar();
void bar(int *);
void bar(float *);
template<typename TT> static void foo(std::vector<TT*> &vec);
};
template<typename TT>
void CC::foo(std::vector<TT*> &vec) {
using ::bar;
TT *tt;
bar(tt);
vec.push_back(tt);
}
class Argh {};
void bar(Argh *&aa) { aa = new Argh; }
class Blah {};
void bar(Blah *&bb) { bb = new Blah; }
int main(int argc, char *argv[]) {
std::vector<Blah*> vec;
CC::foo(vec);
return 0;
}
Nobody has yet pointed out any part of the current Standard that says I can't.
C++03 does not make the name ::bar dependent. Dependency happens for type names by dependent types, and for non-type names by dependent expressions that are either type or value dependent. If a name is looked up in a dependent type, it becomes a type-dependent id-expression (14.6.2.2/3 last bullet), and its lookup is delayed until instantiation. The name ::bar is no such dependent expression. If you were to call bar(tt), a special rule of C++03 at 14.2.6 says
In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2).
So you need to remove the :: in order to make it an identifier and to make it dependent by this special rule.
The reason I can't remove the :: is that in my real code, the template function foo is a member function of class CC, and there exist a family of overloaded member functions CC::bar(...), meaning I need to qualify ::bar(TT*) to avoid defaulting to CC::bar(...). That's what :: exists for, I'm surprised if the Standard says I can't use :: here
The proper way to solve it is to introduce a using declaration into the local scope of your function.
namespace dummies { void f(); }
template<typename T>
struct S {
void f();
void g() {
using dummies::f; // without it, it won't work
f(T()); // with ::f, it won't work
}
};
struct A { };
void f(A) { } // <- will find this
int main() {
S<A> a;
a.g();
}
ADL will not do anything if ordinary lookup finds a class member function. Therefor, you introduce a using declaration, so ordinary lookup doesn't find a class member function, and ADL can advance the declarations visible when instantiating.
But this seems to disagree with you: Stroustrup TC++PL Sp Ed, Section C.13.8.1, Dependent Names: "Basically, the name of a function called is dependent if it is obviously dependent by looking at its arguments or at its formal parameters"
Stroustrup's book is also written for people who possibly don't know C++ yet. It won't try to cover all rules with 100% accuracy, as is normal for these books. The gory details are left for ISO Standard readers.
Also, the formal parameters of a function have nothing to do with whether a function call is dependent or not. In the IS, only actual arguments define dependency of a function name. This was different in an old draft from 1996, which had the notion of implicit and explicit dependency. Implicitly dependency was defined as
A name implicitly depends on a template-argument if it is a function
name used in a function call and the function call would have a dif-
ferent resolution or no resolution if a type, template, or enumerator
mentioned in the template-argument were missing from the program.
[...]
[Example: some calls that depend on a template-argument type T are:
The function called has a parameter that depends on T according to
the type deduction rules (temp.deduct). For example, f(T),
f(Array), and f(const T*).
The type of the actual argument depends on T. For example, f(T(1)),
f(t), f(g(t)), and f(&t) assuming that t has the type T.
A practical example is also given
This ill-formed template instantiation uses a function that does not
depend on a template-argument:
template<class T> class Z {
public:
void f() const
{
g(1); // g() not found in Z's context.
// Look again at point of instantiation
}
};
void g(int);
void h(const Z<Horse>& x)
{
x.f(); // error: g(int) called by g(1) does not depend
// on template-argument ``Horse''
}
The call x.f() gives rise to the specialization:
void Z<Horse>::f() { g(1); }
The call g(1) would call g(int), but since that call does not depend
on the template-argument Horse and because g(int) was not in scope at
the point of the definition of the template, the call x.f() is ill-
formed.
On the other hand:
void h(const Z<int>& y)
{
y.f(); // fine: g(int) called by g(1) depends
// on template-argument ``int''
}
Here, the call y.f() gives rise to the specialization:
void Z<int>::f() { g(1); }
The call g(1) calls g(int), and since that call depends on the tem-
plate-argument int, the call y.f() is acceptable even though g(int)
wasn't in scope at the point of the template definition. ]
These things are left to history, and even the last traces from it are disappearing slowly, albeit not actively driven (n3126 for instance gets rid of "explicitly depends" at [temp.names]/p4 as a side-effect of another change, because the distinction between "explicitly depends" and "implicitly depends" has never existed in the IS).
From section 14.7.2 of the C++ spec:
In an expression of the form:
postfix-expression ( expression-listopt )
where the postfix-expression is an unqualified-id but not a template-id , the unqualified-id denotes a dependent
name if and only if any of the expressions in the expression-list is a type-dependent expression (14.7.2.2).
since ::b is not an unqualified id, it is not a dependent name. If you remove the ::, it is an unqualified name and so is a dependent name. For a non-dependent name, the lookup occurs at the point of the template declaration, not the instantiation, and at that point there is no global declaration of bar visible, so you get an error.
This ugliness works with Intel C++ 11.0 and perhaps illuminates the compiler's point of view:
#include <vector>
#include <iostream>
// *********************
// forward declare in the global namespace a family of functions named bar
// taking some argument whose type is still a matter of speculation
// at this point
template<class T>
void bar(T x);
// *********************
template<typename TT>
void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
public:
};
void bar(Blah *x)
{
// I like output in my examples so I added this
std::cout << "Yoo hoo!" << std::endl;
}
// **********************
// Specialize bar<Blah*>
template<>
inline
void bar<Blah*>(Blah *x) { ::bar(x); }
// **********************
int main(int, char *)
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
This should work, your problem is the declaration order:
// hello.cpp
#include <vector>
class Blah
{
public:
};
void bar(Blah *&)
{ }
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);
return 0;
}
A dependent name still requires a function declaration. Any function declaration with that name will do, but there must be something. How else would the compiler disambiguate an overloaded function call from, say, a misspelled functor object? In other words, finding some function of that name, thus verifying that overloading on that name is possible, instigates the overload resolution process in qualified (or unqualified) name lookup.
// hello.cpp
#include <vector>
void bar(); // Comeau bails without this.
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
class Blah
{
};
void bar(Blah *&)
{
}
int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
//foo(vec); - instanting it is certainly an error!
return 0;
}
Your code works fine on VS2005. so it indeed seems like a bug in gcc. (I don't know what the specs say about this, maybe someone will come along and post it.)
As for gcc, I also tried defining a different overload of bar before foo, so that the symbol bar is at least defined:
void bar(float *) {
}
template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}
void bar(int *) {
}
int main(int argc, char *argv[])
{
std::vector<int*> vec;
foo(vec);
return 0;
}
but gcc is still totally blind to the int * overload:
error: cannot convert int* to float* for argument 1 to void bar(float*)
It seems gcc will only use those functions that are defined before the template itself.
However, if you remove the explicit :: specifier and make it just bar(tt), it seems to work fine. Chris Dodd's answer seems satisfactory in explaining why this is so.

How do I call a friend template function defined inside a class?

I got this example from my book, but I have no idea how to actually call the ticket function. This is the code:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
I get the "candidate function(s) not accessible" error message.
A few points will help you figure out what's going on here:
I) Friend function definitions within classes can only be found by Argument dependent lookup when called from outside the class definition.
II) Function templates that are supplied explicit template arguments do not undergo ADL unless the compiler is given some explicit help in identifying the call as a function call.
III) Argument dependent lookup (ADL) only works for user defined types.
A few examples will better illustrate each of the above points:
//------------------------
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
};
S s;
int i = f(3); // error - ADL does not work for ints, (III)
int j = f(s); // ok - ADL works for UDTs and helps find friend function - calls 2 (III)
// so how do we call function 1? If the compiler won't find the name via ADL
// declare the function in the namespace scope (since that is where the friend function
// gets injected)
int f(int); // This function declaration refers to the same function as #1
int k = f(3); // ok - but not because of ADL
// ok now lets add some friend templates and make this interesting
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
template<class T> friend int g(int) { return 0; } // 3
template<class T> friend int g(S) { return 0; } // 4
template<class T> friend int g() { return 0; } // 5
};
S s;
int k = g(5); // error - no ADL (III)
int l = g(s); // ok - ADL - calls 4
int m = g<int>(s); // should call 4 - but no ADL (point II above)
// ok so point II above says we have to give the compiler some help here
// We have to tell the compiler that g<int> identifies a function
// The way to do that is to add a visible dummy template function declaration
template<class /*Dummy*/, class /*TriggerADL*/> void g();
int m = g<int>(s); // ok - compiler recognizes fun call, ADL triggered - calls 4
int n = g<int>(3); // still not ok - no ADL for ints
// so how do we call either function 3 or 5 since we cannot rely on ADL?
// Remember friend functions are injected into the outer namespace
// so lets just declare the functions in the outer namespace (as we did above)
// both these declarations of g below refer to their counterparts defined in S
template<class T> int g(int);
template<class T> int g();
int o = g<int>(3); // ok
int p = g<int>(); // ok
// Of course once you have these two declarations at namespace scope
// you can get rid of the Dummy, TriggerADL declaration.
Ok so now lets return to the Vandevoorde example that you quoted, and now this should be easy:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter;
template<class T> int ticket(); // <-- this should work with a conformant compiler
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Hope that helps :)
Hotfix
There is a hot-fix available, but read the below explanation if you want to understand what's going on.
#include <iostream>
template<typename T> int ticket();
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter; // don't forget the definition
int main() {
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
As the snippet shows, you have to declare the template to make it visible when you call it.
Friend function definitions
This is confusing, since there are some rules in the way in this case. Some basic points, and then some other points.
struct A {
friend void f(A*) { std::cout << "hello"; }
};
What does it do? It defines a friend function. Such a function is a member of the enclosing namespace. It's not a class member, even though it is defined within a class! The fact that it's defined within a class only changes the lexical scope of that function: It can refer to that class' members directly, without preceding the class-name.
Most importantly, though, the function is not visible after being declared. You cannot take its address doing something like this, for example
&f
The only way that the function would work is using argument dependent lookup. A lookup that ends up having that class as its associated class will consider that friend function. That means that the following works:
f((A*)0);
It works because the call includes an argument with type that has the class included. In that case, the class is an associated class, and the friend declaration will be considered.
The following won't work, for example
f(0);
Because it has no idea that it should look within A to find a friend declaration. A friend function definition of a function without an argument won't be found, because there is no argument dependent lookup happening, then.
Friend function definition for templates
In addition to the fact that your call does not include arguments, it has another problem. If you define a friend function template, the matter is more complicated. There is a rule that says that if the compiler sees T<A1, A2, A3>, that this only refers to a template specialization if T actually resolves to a template. Consider
ticket < int > ()
The compiler can't resolve ticket, because it is not visible to normal lookup. Therefor, the rule says that ticket<int> does not refer to a function. It has to be parsed as a relational expression, yielding to the following
(ticket < int) > ()
That will be a syntax error, because int is not a value, and () is neither a value.
Example
Here is an example where it matters.
struct A {
template<int I> friend void f(A*) { }
};
// try to comment this out
template<typename Dummy> void f();
int main() {
f<1>((A*)0);
}
That compiles. It compiles because f resolves to a template (although a completely different one that can't even accept a non-type template argument - but that doesn't matter!). But a Standard conforming compiler will not compile the snippet once you comment out the second declaration, because it's compiled as a relational expression (less-than and smaller-than) and it will not find symbol f.
Read this thread for further information: What am I missing in this template toy example?.
I do get the same error using the MS VS++ compiler. According to the docs on MSDN:
http://msdn.microsoft.com/en-us/library/h2x4fzdz(VS.80).aspx
Friends are not in the class's scope,
and they are not called using the
member-selection operators (. and –>)
unless they are members of another
class. A friend function is declared
by the class that is granting access.
So friend functions are not actually part of the class and should therefore not be defined in class scope. Define the function outside of the class:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket();
static int counter;
};
template<typename T>
int ticket() {
return ++Manager::counter;
}
int Manager::counter;
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Why not make it static instead?
#include <iostream>
class Manager {
public:
template<typename T>
static int ticket()
{
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << Manager::ticket<int>() << std::endl;
}
Though really, it doesn't have to be a template either. I assume you needed information specifically about friend templates?