C ++ adds a friend to a template class to give a type

I'm currently reading Effective C ++, and there is a chapter that contains code similar to this:

template <typename T> class Num { public: Num(int n) { ... } }; template <typename T> Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... } Num<int> n = 5 * Num<int>(10); 

The book says that this will not work (and it really is not), because you cannot expect the compiler to use implicit typecasting to specialize the template.

As a permission, it is proposed to use the "friend" syntax to define a function within a class.

 //It works template <typename T> class Num { public: Num(int n) { ... } friend Num operator*(const Num& lhs, const Num& rhs) { ... } }; Num<int> n = 5 * Num<int>(10); 

And the book suggests using this declaration to declare when I need an implicit conversion to a template class type. And all this makes sense.

But why can't I get the same example that works with a generic function, not an operator?

 template <typename T> class Num { public: Num(int n) { ... } friend void doFoo(const Num& lhs) { ... } }; doFoo(5); 

This time, the compiler complains that it cannot find doFoo at all. And if I declare doFoo outside the class, I get a reasonable error of inappropriate types. It seems that the "friend ..." part is simply ignored.

So is there a problem with my understanding? What is the difference between a function and an operator in this case?

+8
c ++ templates
source share
3 answers

The reason is that here

 doFoo(5); 

the compiler cannot find foo , given the int parameter. This will be the equivalent of calling your friendโ€™s operator as follows:

 Num<int> n = 5 * 10; 

This will work, but not by calling the friend operator* defined in your Num class, but by calling the built-in operator* for integers, and then using the implicit conversion from the Num conversion constructor.

+3
source share

The main problem is the search. The friend declaration provides a declaration of the namespace level function, but the declaration is only available inside the class that makes friends with it. In this example, the book provides that this is not a problem: a function takes two arguments of a nested type, if one of them has a private type, Argument Dependent Lookup will look into the class definition and find the operator. In your case, this is not so, since there is one argument and a conversion is required, the compiler will not look for class definitions.

Note that this is independent of patterns and transformations:

 class A { friend void f( int ) {} friend void g( int, A ) {} }; int main() { f(5); // Error: lookup cannot find 'f' declared *only* inside A g(5,A()); // Ok, one argument is 'A', lookup will find the function } 

In the above case, when there are no templates, you can add a declaration at the namespace level to fix it, but this is not really an option for template classes.

 class A { friend void f() { std::cout << "inside A\n"; } }; void f(int); // only declaration int main() { f(5); // "inside A" } 

This cannot be done for the template (and for all types of instances), since a friend declaration is a declaration of a non-templated function. Although you can play with the code for testing only:

 template <typename T> struct Num { Num(int x) ... friend void f( Num const & ); }; Num<int> f(Num<int> const &); // only declaration int main() { f(5); } 
+1
source share

Yes, this code compiler does not know how to work with it. like doFoo (5)

the compiler does not know that 5 is an int

0
source share

All Articles