here is my code
head.h
template <class T>
class Ext;
template <class T>
void fun(const Ext<T>&);
template <class T>
class Ext {
friend void fun<T>(const Ext<T>&);
private:
class Inner;
Inner* p;
};
template <class T>
void fun2(const typename Ext<T>::Inner&);
template <class T>
class Ext<T>::Inner {
friend class Ext<T>;
friend void fun<T>(const Ext<T>&);
friend void fun2<T>(const typename Ext<T>::Inner&);
private:
Inner* q;
int a;
Inner() : a(1) {}
};
template <class T>
void fun2(const typename Ext<T>::Inner& i) {
std::cout << i.a << std::endl;
}
template <class T>
void fun(const Ext<T>& e) {
typename Ext<T>::Inner y;
y.a = 3;
fun2<T>(y);
}
main.cpp
int main() {
Ext<int> x;
fun(x);
}
g++ and (look below) clang give an
class Ext<int>::Inner’ is private within this context
So my question is : Is there a way to do this without making the inner class public? And why if i replace fun anf fun2 with an overload operator<< then it compiles even with inner class private (ONLY WITH CLANG)? like this
head.h
#include <iostream>
template <class T>
class Ext;
template <class T>
std::ostream& operator<<(std::ostream&, const Ext<T>&);
template <class T>
class Ext {
friend std::ostream& operator<< <T>(std::ostream&, const Ext<T>&);
private:
class Inner;
Inner* p;
};
template <class T>
std::ostream& operator<<(std::ostream&, const typename Ext<T>::Inner&);
template <class T>
class Ext<T>::Inner {
friend class Ext<T>;
friend std::ostream& operator<< <T>(std::ostream&, const typename Ext<T>::Inner&);
private:
Inner* q;
int a;
Inner() : a(1) {}
};
template <class T>
std::ostream& operator<<(std::ostream& os, const typename Ext<T>::Inner& n) {
return os << n.a << " ";
}
template <class T>
std::ostream& operator<<(std::ostream& os, const Ext<T>& t) {
os << "[ ";
operator<< <T>(os, *(t.p));
os << "] ";
return os;
}
main.cpp
int main() {
Ext<int> x;
std::cout << x << std::endl;
}
i tried to compile with diffrent compilers but nothing works if i dont compile with clang and in that case its only compiles when the funcion is an overload of an operator
Is there a way to do this without making the inner class public?
Yes, but there are several problems with the code all of which are explained and solved below.
First, friend
ship is not associative in C++. This means that you need to add a friend template declaration for fun2
inside the class template Ext
as shown in the code below.
Second, the friend declaration that you currently have are non-template friend declarations. But since fun
and fun2
are templates, you will need to change these to friend template declarations which is done by adding template<typename U>
in the code shown below.
The comments are also added in the below program to make it easier to spot the changes:
#include <iostream>
template <class T>
class Ext;
template <class T>
void fun(const Ext<T>&);
template <class T>
class Ext {
template<typename U> //added this template<typename U>
friend void fun(const Ext<U>&);
//added this friend template declaration
template <class U>
friend void fun2(const typename Ext<U>::Inner& i);
private:
class Inner;
Inner* p;
};
template <class T>
void fun2(const typename Ext<T>::Inner&);
template <class T>
class Ext<T>::Inner {
template<typename U> //added this template<typename U>
friend void fun(const Ext<U>&);
template <class U> //added this template<typename U>
friend void fun2(const typename Ext<U>::Inner& i);
private:
Inner* q;
int a;
Inner() : a(1) {}
};
template <class T>
void fun2(const typename Ext<T>::Inner& i) {
std::cout << i.a << std::endl;
}
template <class T>
void fun(const Ext<T>& e) {
typename Ext<T>::Inner y;
y.a = 3;
fun2<T>(y);
}
int main() {
Ext<int> x;
fun(x);
}
Now the program works with all compilers.