tags:

views:

888

answers:

5

hi guys please help me with this function 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 msg thanks alot for looking!

+2  A: 

this works for me (GCC 4.2.3):

#include <iostream>

class Manager {
public:
    template<typename T>
        friend int ticket() {
            return ++Manager::counter;
        }
    static int counter;
};

int Manager::counter;

int main()
{
    std::cout << "ticket: " << ticket<int>() << std::endl;
    std::cout << "ticket: " << ticket<int>() << std::endl;
}

what compiler are you using?

Piotr Findeisen
o i was missing the definition of counter right? i had only declared it (i think..)I tried your code but i still get the same error, maybe something wrong with my compilerthanks for replying ^_^
pyralis
A good point that Manager::counter needs to be declared explicitly.
rlbond
A: 

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?

rlbond
yes i was learning how to defined friend functions templates, the class compiles but when i try to actually call it i cant,im using a trial of VS 9 thanks alot all for your help :]
pyralis
i just tried Piotr Findeisen's code on code::blocks and compiles finethanks alot you guys :D
pyralis
+4  A: 

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;
}
heavyd
o this explains the VS issue, thanks a lot for posting it :D
pyralis
+6  A: 

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 :)

Faisal Vali
+1. I don't know why this hasn't got more points, it's already one hour old by now and i think it's a great one :)
Johannes Schaub - litb
+4  A: 

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?.

Johannes Schaub - litb
thank you for posting this!, great info i did not know about friend declarations :]
pyralis