Reputation: 1951
In order for some global function
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
to be able to access to the private field value
of some templated class
template<typename T>
class Obj {
public:
Obj (T value);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {}
we need to declare func<T, count>
a friend of Obj<T>
. But func<T, count>
has to be declared before we can make it a friend of Obj<T>
, and for this we need to forward-declare Obj<T>
. The resulting code looks like this
// Forward declarations
template<typename T>
class Obj;
template<typename T, int count>
void func (const Obj<T>& obj);
// Obj<T>
template<typename T>
class Obj {
public:
Obj (T value);
template<int count>
friend void func<T, count> (const Obj<T>& obj);
private:
T value;
};
template<typename T>
Obj<T>::Obj (T value) : value(value) {} // <-- ERROR
// func<T>
template<typename T, int count>
void func (const Obj<T>& obj) {
for (int i = 0; i < count; i++)
std::cout << obj.value << std::endl;
}
But this makes gcc complain about the "invalid use of template-id 'func' in declaration of primary template", so how do I actually declare func<T, count>
a friend of Obj<T>
for every count
? According to this answer I just need to replace the friend declaration with this
template<typename T1, int count>
friend void func (const Obj<T1>& obj);
As far as I know this would make func<T1, count>
a friend of Obj<T>
regardless of whether T1
and T
match, which is absurd. Is it possible to declare func<T, count>
a friend of Obj<T>
and no other Obj<T1>
? (preferably in a way that keeps the definition of func<T, count>
outside the definition of Obj<T>
)
(I know I could just make count
a real parameter, but the example above is just a simplification of my real code. In reality I'm trying to overload std::basic_ostream<CharT, Traits>& operator<< (std::basic_ostream<CharT, Traits>& stream, const Obj<T>& obj)
for some class Obj<T>
in a way that allows operator<<
to access private fields of Obj<T>
.)
Upvotes: 0
Views: 51
Reputation: 409364
The friend
declaration must match any possible forward declaration, and of course the definition, including template arguments.
That means you need e.g.
template<typename U, int count>
friend void func(const Obj<U>& obj);
It doesn't matter if the class template argument T
and the function template argument U
are different, as the calls will be made to the correct function anyway.
Example:
Obj<int> int_obj;
Obj<float> float_obj;
func<X>(int_obj); // Will call void func<int, X>(int_obj)
func<X>(float_obj); // Will call void func<float, X>(float_obj)
As an alternative, you can define the function inline in the class definition, and then you don't need to provide the T
or U
template arguments:
template<int count>
friend void func(const Obj<T>& obj)
{
// Implementation...
}
And in neither case you should really have a forward declaration of func
(as mentioned in my comment).
Upvotes: 1