That is a good observation. The rule of thumb is to prefer non-member non-friend functions: GotW #84: Monoliths "Unstrung".Quote:
Originally Posted by kempofighter
Printable View
That is a good observation. The rule of thumb is to prefer non-member non-friend functions: GotW #84: Monoliths "Unstrung".Quote:
Originally Posted by kempofighter
That's not actually true. Friend functions can be defined within the class and, in the case of templates, can make the code easier to write. I had such a scenario where I was overloading various operators for a templated class (+-<). Defining the operators outside of the class caused problems that required extra code to get the normal operator functionality (I can't remember what the code was exactly). Defining the functions within the class was much simpler.Quote:
The OP defined the function within the class which is incorrect. It needs to be declared as a friend but defined globally.
EDIT : I've been trying to remember how to reproduce the problem, but it was a long time ago. :confused:
I know I'm stating the obvious, and I'm certainly not disagreeing with you, but although the standard specifies you can do this, you can only do it if the compiler supports it, and some don't. For this reason, and it is my preference, I tend to separate the declaration and definition.
Also, I would have thought that for templated classes, the friend function should really have it's own template definition and not assume to inherit the class one. The reason being that if the friend function is extracted out of the class, it will need a template definition that matches that of the declaration, and that, as far as I am aware, needs to be an explicit template definition, and not one that is implied from the class template definition.
For example, the following does not compile, because, due to the lack of a function template definition on the function declaration it fails to associate the friend declaration with global definition.
Where as adding an explicit function template definition fixes the association issue...Code:template<typename T>
class MyClass
{
public:
MyClass(T val)
:val_(val)
,name_("MyClass")
{}
friend std::ostream& operator<<(std::ostream& o, const MyClass<T>& m);
private:
T val_;
std::string name_;
};
template<typename T>
std::ostream& operator<<(std::ostream& o, const MyClass<T>& m)
{
o << m.name_ << " holds the value " << m.val_ << std::endl;
return o;
}
Now I realise that when you define a template function in the class, its declaration is also its definition and therefore there are no problems associating the two, but somehow:Code:template<typename T>
class MyClass
{
public:
MyClass(T val)
:val_(val)
,name_("MyClass")
{}
template<typename U>
friend std::ostream& operator<<(std::ostream& o, const MyClass<U>& m);
private:
T val_;
std::string name_;
};
template<typename U>
std::ostream& operator<<(std::ostream& o, const MyClass<U>& m)
{
o << m.name_ << " holds the value " << m.val_ << std::endl;
return o;
}
doesn't feel right - but I can't put my finger on the reason why. If I was forced to write the definition inside the class, I would much prefer to write:Code:template<typename T>
class MyClass
{
public:
MyClass(T val)
:val_(val)
,name_("MyClass")
{}
friend std::ostream& operator<<(std::ostream& o, const MyClass<T>& m)
{
o << m.name_ << " holds the value " << m.val_ << std::endl;
return o;
}
private:
T val_;
std::string name_;
};
Code:template<typename T>
class MyClass
{
public:
MyClass(T val)
:val_(val)
,name_("MyClass")
{}
template<typename U>
friend std::ostream& operator<<(std::ostream& o, const MyClass<U>& m)
{
o << m.name_ << " holds the value " << m.val_ << std::endl;
return o;
}
private:
T val_;
std::string name_;
};
Am I missing something?? :confused::confused:
If the compiler states something is legal, and the compiler will not allow it, isn't that prima facia evidence that you have a non-conformant compiler????
(I admit I have not checked the wording of the specificiation)
No you're not missing anything, you are correct, the result is that if it isn't supported that the compiler is non-standard.