C ++: how can I call a friend template function defined inside a class?

Hi guys, please help me with this function. I got this example from my book, but I have no idea how to actually name 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 an "unavailable candidate function" msgstr Thank you very much for the search!

+2
c ++ templates
source share
5 answers

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; } 

which compiler are you using?

+1
source share

A few points will help you understand what is happening here:

I) The definitions of friend functions in classes can only be found using an Argument-dependent search when calling the class definition from outside.

II) Function templates that are supplied with explicit template arguments are not exposed to ADL unless explicit assistance is provided to the compiler in defining a call as a function call.

III) The dependent search (ADL) argument only works for user-defined types.

A few examples will illustrate each of the above points better:

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

So, now back to the Vandevoorde example you specified, 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 this helps :)

+9
source share

corrections

There is a hot fix, but read the explanation below if you want to understand what is 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 must declare a template so that it displays when you call it.

Friend Function Definitions

This is confusing, as there are some rules in this case. Some highlights, and then some other highlights.

 struct A { friend void f(A*) { std::cout << "hello"; } }; 

What is he doing? It defines the function of a friend. Such a function is a member of the encompassing namespace. This is not a member of the class, although it is defined inside the class! The fact that it is defined in a class only changes the lexical domain of this function: it can directly refer to members of this class without preceding the class name.

Most importantly, however, the function is not visible after the announcement. You cannot make your address like this, for example

 &f 

The only way the function will work is to use an argument-dependent search. A search that ends with this class as an associated class will consider this friend function. This means that the following work:

 f((A*)0); 

This works because the call includes an argument with the type the class is included in. In this case, the class is an associated class, and a friend’s declaration will be considered.

The following actions will not work, for example

 f(0); 

Because he does not know that he must look for A to find a friend’s ad. The function of determining the function of a friend without an argument will not be found, because after that there is no search dependent on the argument.

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, things are more complicated. There is a rule that says that if the compiler sees T<A1, A2, A3> , this only applies to the specialization of the template, if T actually resolves the template. Consider

 ticket < int > () 

The compiler cannot resolve ticket because it does not appear in a normal search. Therefore, the rule states that ticket<int> not a function. It should be analyzed as a relational expression, which leads to the following

 (ticket < int) > () 

This will be a syntax error because int not a value and () not 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); } 

It compiles. It compiles because f resolves the pattern (although it is completely different, which cannot even accept a non-type pattern argument), but it does not matter!). But the standard compatible compiler will not compile the fragment as soon as you comment out the second declaration, because it is compiled as a relational expression (less and less), and it will not find the character f .

Read this topic for more information: What am I missing in this template game example? .

+5
source share

I get the same error using MS VS ++ compiler. According to the docs on MSDN:

http://msdn.microsoft.com/en-us/library/h2x4fzdz(VS.80).aspx

Friends are not members of the class, and they are not called using member selection operators (. And →) unless they are members of another class. A friend function has been declared on the access class.

Thus, the functions of friends are not actually part of the class and therefore should not be defined in the class. Define a function outside 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; } 
+4
source share

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; } 

Although in reality this also should not be a template. I assume that you need information specifically about friends templates?

0
source share

All Articles