illegal friend templates?

L

LuB

Is this somehow illegal?


template<typename T>
class A {

public:

private:

friend class T;

int intVal;

};


class B {
public:
int init (A<B>& a)
{
a.intVal = 6;
}
};

....

error C2248: 'A<T>::intVal' : cannot access private member declared in
class 'A<T>'
 
L

Luke Meyers

LuB said:
Is this somehow illegal?

template<typename T>
class A {
private:
friend class T;
};

My compiler (gcc 4.0.2) complains at this point because T is not
necessarily a class. Only classes can be friends. Since according to
this, your program is illegal from this point on, there's not much
point in speculating about what's going on later. Either your compiler
is wrong and it's 'nuff said, or mine is wrong and we've learned
something and can proceed. Given that mine is a recent version of gcc,
I'd lean towards the former likelihood.

Luke
 
L

LuB

Not sure what you mean. Both our compilers failed. Why is mine wrong
and yours right or vice versa? Did you notice the error at the end of
the post?

At any rate, after a bit more trial and error, substitute


friend typename T;

for

friend class T;



That successfully compiles in MSVC 2005.

Thanks,

-Luther


....Sorry if this is a TOP post. Google only has so much flexibility.
 
L

Luke Meyers

LuB said:
Not sure what you mean. Both our compilers failed. Why is mine wrong
and yours right or vice versa? Did you notice the error at the end of
the post?

Please quote what you're replying to, as a matter of standard Usenet
courtesy.

Both compilers did not "fail," in the sense of doing something wrong.
They each produced errors. However, my compiler produced an error at
an earlier point -- if it was correct to do so, then your compiler may
have been incorrect to *not* produce an error at the same point. Based
on the reasoning I provided (which you ignored?), and the fact that gcc
is has a reputation for being far more standards-compliant than MSVC,
it seems far more likely that your compiler is doing the wrong thing
here, in the sense of providing nonstandard behavior. If that's the
case, it's useless and/or off-topic to speculate further about the
consequences of said nonstandard behavior.
At any rate, after a bit more trial and error, substitute

friend typename T;

for

friend class T;

That successfully compiles in MSVC 2005.

I don't have my copy of the standard with me (keep it at work), but I
suspect that while this works on your compiler, it's not correct
according to the standard. My reasoning is based on the fact that only
certain types (classes and functions) can be friends. Since your T can
be anything, including types which are not eligible for friendship, the
compiler objects. This is kind of a nitpick, but it's the sort of
nitpick C++ compilers tend to make. It's also the sort of thing MSVC
implementors are apt to ignore.

Anyway, it's nice that you got it working on your compiler. If you
don't need your code to be portable between platforms, compilers, or
compiler versions, or be standards-compliant, then you're all set.

Does the standard even allow "friend typename" used in this way? I'm a
little suspicious of that, too.
...Sorry if this is a TOP post. Google only has so much flexibility.

You didn't top-post, you failed to quote entirely. If you click
"options" at the top of the message, and click "reply" from there,
you'll get a proper quote to work with. I'm posting this from Google
as well, and as you can see I quote just fine.

Luke
 
K

Kai-Uwe Bux

Luke said:
LuB said:
Is this somehow illegal?

template<typename T>
class A {
private:
friend class T;
};

My compiler (gcc 4.0.2) complains at this point because T is not
necessarily a class. Only classes can be friends. [snip]

I think that cannot be the reason your compiler complains: such a check
would be postponed until the template is instantiated. Then, if the actual
type passed is not a class, you should see an error.



However, the code is illegal because the standard explicitly says so in
[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.


Support for this provision in g++ is a little flaky and you can sometimes
fool the compiler. For instance, g++ (4.1.0) still accepts the following
*illegal* code:

template < typename T >
class identity {
public:

typedef T me;

};

template < typename T >
class my_friend {
private:

friend class identity< T >::me;

char x;

};

class The_T {
public:

static
char & peek_friend ( my_friend< The_T > & f ) {
return( f.x );
}

};

int main (void) {
my_friend< The_T > x;
}




Best

Kai-Uwe Bux
 
L

Luke Meyers

Kai-Uwe Bux said:
Luke said:
LuB said:
Is this somehow illegal?

template<typename T>
class A {
private:
friend class T;
};

My compiler (gcc 4.0.2) complains at this point because T is not
necessarily a class. Only classes can be friends. [snip]

I think that cannot be the reason your compiler complains: such a check
would be postponed until the template is instantiated. Then, if the actual
type passed is not a class, you should see an error.

I get the same error with the following complete program:

template<class T>
class A
{
friend class T;
};

int main () { return 0; }

I guess gcc just doesn't trust me not to instantiate it.
However, the code is illegal because the standard explicitly says so in
[7.1.5.3/2]:

Nice, thanks very much for the cite. I don't suppose I could convince
you to take a look at the unique_copy constness issue I encountered in
another thread? No bites so far (though it's early yet)... :)

Cheers,
Luke
 
L

LuB

Luke said:
Please quote what you're replying to, as a matter of standard Usenet
courtesy.

Both compilers did not "fail," in the sense of doing something wrong.
They each produced errors. However, my compiler produced an error at
an earlier point -- if it was correct to do so, then your compiler may
have been incorrect to *not* produce an error at the same point. Based
on the reasoning I provided (which you ignored?), and the fact that gcc
is has a reputation for being far more standards-compliant than MSVC,
it seems far more likely that your compiler is doing the wrong thing
here, in the sense of providing nonstandard behavior. If that's the
case, it's useless and/or off-topic to speculate further about the
consequences of said nonstandard behavior.


I don't have my copy of the standard with me (keep it at work), but I
suspect that while this works on your compiler, it's not correct
according to the standard. My reasoning is based on the fact that only
certain types (classes and functions) can be friends. Since your T can
be anything, including types which are not eligible for friendship, the
compiler objects. This is kind of a nitpick, but it's the sort of
nitpick C++ compilers tend to make. It's also the sort of thing MSVC
implementors are apt to ignore.

Anyway, it's nice that you got it working on your compiler. If you
don't need your code to be portable between platforms, compilers, or
compiler versions, or be standards-compliant, then you're all set.

Does the standard even allow "friend typename" used in this way? I'm a
little suspicious of that, too.


You didn't top-post, you failed to quote entirely. If you click
"options" at the top of the message, and click "reply" from there,
you'll get a proper quote to work with. I'm posting this from Google
as well, and as you can see I quote just fine.

Luke

It was a simple question ... why all the ridicule?
 
L

LuB

Kai-Uwe Bux said:
Luke said:
LuB said:
Is this somehow illegal?

template<typename T>
class A {
private:
friend class T;
};

My compiler (gcc 4.0.2) complains at this point because T is not
necessarily a class. Only classes can be friends. [snip]

I think that cannot be the reason your compiler complains: such a check
would be postponed until the template is instantiated. Then, if the actual
type passed is not a class, you should see an error.



However, the code is illegal because the standard explicitly says so in
[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.
....

Best

Kai-Uwe Bux


Thank you for the elaboration Kai. Very much appreciated. I believe
I'll need a different approach.

-Luther
 
L

Luke Meyers

LuB said:
It was a simple question ... why all the ridicule?

I find it unfortunate that you interpreted any of what I said as such.
It was certainly not my intent, and I wonder if you could find your way
to a more charitable interpretation. It might help to consider a few
points of local culture:

1. Many who frequent this group, myself included, are more-than-usually
precise with our language. This pays off in various ways and is
generally a Good Thing, but can occasionally come off as abrasive to
the uninitiated. This is particularly prone to occur when
disambiguating language one is responding to (e.g. your term "fail").

2. It's of pragmatic importance to assertively reinforce norms
regarding what is and is not on-topic. In particular, discussion
begins and ends (or is meant to) where the C++ standard does -- hence,
it's not a good idea to let a conversation drift into discussion of,
for example, questions deriving from the consequences of nonstandard
extensions a particular compiler happens to provide. There are fora
for such things; this is not one of them.

3. Factual statements containing no value judgements generally best not
taken as personal attacks, even if you don't like what they imply about
your favorite compiler, newsreader, etc.

Nothing I said was intended to impugn or ridicule anyone. My
statements of fact regarding norms of Usenet etiquette and the
mechanics of Google Groups, the current and historical level of
standards-compliance in the MSVC compiler, various terminology, the
contents of the C++ standard, and your options regarding portability
and compliance were all intended as just that -- factual statements
with no value judgements implied or desired.

I hope this explanation satisfies you, and that you will in future be
less prone to take offense from those who behave civilly and make no
attempt to give it. Especially when they're trying to provide help you
requested, hmm?

Luke
 

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,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top