I was struggling with the issue described in this question (declaring a template function as a friend of a template class), and I believe the 2nd answer is what I want to do (forward declare the template function, then name a specialization as a friend). I have a question about whether a slightly different solution is actually correct or just happens to work in Visual C++ 2008.
Test code is:
#include <iostream>
// forward declarations
template <typename T>
class test;
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t);
template <typename T>
class test {
friend std::ostream& operator<< <T>(std::ostream &out, const test<T> &t);
// alternative friend declaration
// template <typename U>
// friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
// rest of class
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t) {
// output function defined here
}
First, one strange thing I found was that if I change the forward declaration of operator<<
so that it doesn't match (for example, std::ostream& operator<<(std::ostream &out, int fake);
, everything still compiles and works correctly (to be clear, I don't need to define such a function, only declare it). However, as in the linked-to question, removing the forward declaration causes a problem as the compiler seems to think I'm declaring a data member instead of a friend function. I'm pretty sure that this behaviour is a Visual C++ 2008 bug.
The interesting thing is when I remove the forward declarations and use the alternative friend declaration in the code above. Note that the template parameter U
doesn't appear in the following signature. This method also compiles and works correctly (without changing anything else). My question is whether this is conforming to the standard or an idiosyncrasy of Visual C++ 2008 (I couldn't find a good answer in my reference books).
Note that while a friend declaration template <typename U> friend ... const test<U> &t);
also works, this actually gives each instance of the operator friend
access to any instance of test
, while what I want is that the private members of test<T>
should only be accessible from operator<< <T>
. I tested this by instantiating a test<int>
inside the operator<<
and accessing a private member; this should cause a compile error when I try to output a test<double>
.
Synopsis: Removing the forward declarations and switching to the alternative friend declaration in the code above seems to produce the same result (in Visual C++ 2008) -- is this code actually correct?
UPDATE: Any of the above modifications to the code don't work under gcc, so I'm guessing that these are errors or "features" in the Visual C++ compiler. Still I'd appreciate insights from people familiar with the standard.
See Question&Answers more detail:os