template friend class

K

Kira Yamato

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?
 
J

Jeff Schwab

Kira said:
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?
 
K

Kira Yamato

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 (*).
 
P

Pavel

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, ...>.
Not sure how to do it conveniently, but just wondering why are you
trying to do it? The only thing the member_accessor will be able to do
is to call get_x, set_x which are public anyway and could be called
directly. I would argue it would be sometimes interesting (or at least
funny) to make the accessor object a member of a different class than
the host class of your properties.

Neat idea, by the way! I wonder where it will take you. Let us know.

-Pavel
 
A

aaragon

Not sure how to do it conveniently, but just wondering why are you
trying to do it? The only thing the member_accessor will be able to do
is to call get_x, set_x which are public anyway and could be called
directly. I would argue it would be sometimes interesting (or at least
funny) to make the accessor object a member of a different class than
the host class of your properties.

Neat idea, by the way! I wonder where it will take you. Let us know.

-Pavel

the declaration for a class template is just

template <class someClass> friend class ClassToDeclareAsFriend;

Hope it helps.
 
K

Kira Yamato

the declaration for a class template is just

template <class someClass> friend class ClassToDeclareAsFriend;

I'm not sure I understood your idea. How do I use your idea to get the
following to compile?

template<class C>
class A
{
friend class C;
};
 
K

Kai-Uwe Bux

Kira said:
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?

No. See [7.1.5.3/2]:

3.4.4 describes how name lookup proceeds for the identifier in an
elaborated-type-specifier. If the identifier resolves to a class-name or
enum-name, the elaborated-type-specifier introduces it into the
declaration the same way a simple-type-specifier introduces its type-name.
If the identifier resolves to a typedefname or a template type-parameter,
the elaborated-type-specifier is ill-formed. [Note: this implies that,
within a class template with a template type-parameter T, the declaration

friend class T;

is ill-formed. ] If name lookup does not find a declaration for the name,
the elaborated-type-specifier is ill-formed unless it is of the simple
form class-key identifier in which case the identifier is declared as
described in 3.3.1.


BTW: I do not understand the rationale for this restriction.


Best

Kai-Uwe Bux
 
J

James Kanze

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?

Not at present. The next version of the standard will allow:

template< typename C >
class B
{
friend C ;
} ;

Until then, you're out of luck.
 
K

Kai-Uwe Bux

James said:
Not at present. The next version of the standard will allow:

template< typename C >
class B
{
friend C ;
} ;

I thought that, too; and the wording of the paragraph has changed. However,
in n2521, I find [7.1.6.3/2]:

3.4.4 describes how name lookup proceeds for the identifier in an
elaborated-type-specifier. If the identifier resolves to a class-name or
enum-name, the elaborated-type-specifier introduces it into the
declaration the same way a simpletype- specifier introduces its type-name.
If the identifier resolves to a typedef-name, the
elaborated-type-specifier is ill-formed. [ Note: this implies that, within
a class template with a template type-parameter T, the declaration

friend class T;

is ill-formed. ?end note ]

Note that

a) the note about friend class T being ill-formed is still there, but
b) has no basis in the preceding wording anymore.


I remember that I have posted to comp.std.c++ about this at some point, but
the post dropped dead.


Best

Kai-Uwe Bux
 
J

James Kanze

I thought that, too; and the wording of the paragraph has
changed. However, in n2521, I find [7.1.6.3/2]:
3.4.4 describes how name lookup proceeds for the identifier in an
elaborated-type-specifier. If the identifier resolves to a class-name or
enum-name, the elaborated-type-specifier introduces it into the
declaration the same way a simpletype- specifier introduces its type-name.
If the identifier resolves to a typedef-name, the
elaborated-type-specifier is ill-formed. [ Note: this implies that, within
a class template with a template type-parameter T, the declaration
friend class T;
is ill-formed. ?end note ]
Note that
a) the note about friend class T being ill-formed is still there, but
b) has no basis in the preceding wording anymore.

Note that "friend class T" is (or will be) still ill-formed if T
is a template type parameter, and that the paragraph you quote
is talking only about elaborated-type-specifiers. The latest
draft no longer requires the elaborated-type-specifier in a
friend declaration; you can also write "friend
simple-type-specifier" or "friend typename-specifier".
 
M

Marcel Müller

Hi!

Kira said:
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;
};

Looks like you are trying to implement properties by the backdoor.
But there are more semantics like += which are still not working unless
you pass a bunch of functions or emulate the operators by using get/set
like C# does. I would not recommend the latter because it pretenda a
feature which is not there in effect.
This template allows me to write the following:


class A
{
public:
A() : x(*this) {}

int get_x() const;
void set_x(const int &y);

I would have expected get_x and set_x to be non-public in this case, but
anyway.
member_accessor<A, int, &A::get_x, &A::set_x> 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, ...>.

You can make the constructor protected and derive from member_accessor
within a private class A::my_accessor. This can be a friend of A in the
required specializations.

But I see no reason why the constructor should be private. From the
proxy's point of view this is a public function.

However, I do not see the significant benefit of the whole effort. You
save two braces per access to x. That's it. The "get_" and "set_"
prefixes are not required.


Marcel
 
K

Kai-Uwe Bux

James said:
I thought that, too; and the wording of the paragraph has
changed. However, in n2521, I find [7.1.6.3/2]:
3.4.4 describes how name lookup proceeds for the identifier in an
elaborated-type-specifier. If the identifier resolves to a class-name
or enum-name, the elaborated-type-specifier introduces it into the
declaration the same way a simpletype- specifier introduces its
type-name. If the identifier resolves to a typedef-name, the
elaborated-type-specifier is ill-formed. [ Note: this implies that,
within a class template with a template type-parameter T, the
declaration
friend class T;
is ill-formed. ?end note ]
Note that
a) the note about friend class T being ill-formed is still there, but
b) has no basis in the preceding wording anymore.

Note that "friend class T" is (or will be) still ill-formed if T
is a template type parameter, and that the paragraph you quote
is talking only about elaborated-type-specifiers. The latest
draft no longer requires the elaborated-type-specifier in a
friend declaration; you can also write "friend
simple-type-specifier" or "friend typename-specifier".

Thanks. I missed that.


Best

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top