Re: template friend class
On 2008-02-17 16:46:39 -0500, Jeff Schwab <jeff@schwabcenter.com> said:
Kira Yamato wrote:
A question about declaring a friend class. The following does not compile:
template<class C>
class B
{
public:
friend class C;
};
g++4.0.1 returns the error message
error: using template type parameter 'C' after 'class'
So, is there a way to declare a friend class from the template parameter?
NB: I'm not sure why you want to do this, and I don't necessarily endorse it.
AFAIK, you would have to specialize the template explicitly for each
parameter type. For example:
template<typename C> struct B;
struct S { };
template<> struct B<S> { friend class S; };
You could write a macro to create specializations:
template<typename C> struct B;
#define SPECIALIZE_B(param) \
template<> struct B<param> { friend class param; }
struct S { };
struct T { };
SPECIALIZE_B(S);
SPECIALIZE_B(T);
Btw, why do you actually want this feature?
Well, I'm trying to write a template to implement some inner classes.
To be more specific, I have the following template
template<class C, typename M, M (C::*get)() const, void (C::*set)(const M &)>
class member_accessor : private noncopyable
{
public:
member_accessor(C &c) : c(c) {}
operator M() const { return (c.*get)(); }
member_accessor &operator=(const M &n) { (c.*set)(n); return *this; }
private:
C &c;
};
This template allows me to write the following:
class A
{
public:
A() : x(*this) {}
int get_x() const;
void set_x(const int &y);
member_accessor<A, int, &A::get_x, &A::set_x> x;
};
A a;
a.x = 3; // actually invokes a.set_x(3);
int y = a.x; // actually invokes y = a.get_x();
However, I want to hide the constructor of 'member_accessor' so that
only the container class C can initiate object of type
member_accessor<C, ...>.
The way I thought of doing that is to move the constructor to private
in the member_accessor template and declare the template parameter
class C as friend. That is,
template<class C, typename M, M (C::*get)() const, void (C::*set)(const M &)>
class member_accessor : private noncopyable
{
public:
operator M() const { return (c.*get)(); }
member_accessor &operator=(const M &n) { (c.*set)(n); return *this; }
private:
member_accessor(C &c) : c(c) {} // constructor moved to private.
C &c;
friend class C; // (*) declare class C friend so that C can access
the private constructor.
};
But the g++4.0.1 won't allow line (*).
--
// kira