7

The following code compiles using GCC 4.4.6 and Comeau 4.3.10.

#include <iostream>

struct A { int name; };
template<typename T> struct C : T { using T::name; };
struct B : private A { friend struct C<B>; };

int main()
{
    C<B> o;
    o.name = 0;
}

It gives the following error in VC++10:

main.cpp(4): error C2877: 'A::name' is not accessible from  'A'
main.cpp(10): error C2247: 'A::name' not accessible because 'B' uses 'private' to inherit from 'A'

What's a good cross-compiler workaround that allows o.name = 0;?

Note: Adding using A::name to B takes care of the problem, but publishes the A::name member to everyone, whereas it should only be visible to a particular template instantiation, namely C<B>.

Nick
  • 5,765
  • 5
  • 27
  • 36
  • 2
    Shouldn't that be `using T::name;` ? How is this language feature called ? – J.N. Sep 06 '12 at 07:09
  • Access declarations, see http://stackoverflow.com/questions/2084801/c-using-declaration-scope-and-access-control – Nick Sep 06 '12 at 07:19
  • Please note that the answer to that question states that not using the "using" keyword is deprecated. I know it doesn't solve your problem, but still ;) – J.N. Sep 06 '12 at 07:31
  • By the way, stating the version of VC++ may help. – J.N. Sep 06 '12 at 07:32
  • Ok, I'll just add the `using` keyword, this should kill the red herring. – Nick Sep 06 '12 at 07:32
  • Added the compiler versions, np – Nick Sep 06 '12 at 07:34
  • 1
    What happens if you add `using A::name;` into `B`? – Kerrek SB Sep 06 '12 at 07:39
  • Also you can try `template friend struct C;`. It's a bit different, but maybe it works? – Kerrek SB Sep 06 '12 at 07:46
  • @Kerrek SB, while I only want one particular template instantiation to be a friend, I tried your suggestion to no avail. – Nick Sep 06 '12 at 07:54
  • @Nick: OK, it was just a guess. Your compiler doesn't seem to be standards-compliant, I suppose. – Kerrek SB Sep 06 '12 at 07:56
  • @Kerrek SB, I updated the question regarding `using A::name` w/in `B`. – Nick Sep 06 '12 at 07:57
  • It is definitely not compliant. How do I go about keeping this cross-compiler compatible, ideally w/o writing compiler specific defines? – Nick Sep 06 '12 at 07:58
  • 1
    @Nick: Adding `using A::name` does not have any downsides. It shouldn't be necessary according to the standard, but it definitely has no ill effects. Name lookup comes way before access control. But it also doesn't hurt and doesn't get in the way, so feel free to leave it in. – Kerrek SB Sep 06 '12 at 07:58
  • does `friend struct C` actually do anything in your example? C inherits from B anyway, and B doesn't have any members of its own. Might be it's just me missing some part of C++ knowledge, though ;). – codeling Sep 06 '12 at 08:16
  • 1
    Actually, you could argue that `B` does has a member, namely the privately inherited `A` instance. – Nick Sep 06 '12 at 08:20
  • ah, missed that point, name becoming a private member of B through private inheritance, and therefore accessible for friends, but inaccessible derived classes – codeling Sep 06 '12 at 08:41

2 Answers2

5

Work around is what @kerrekSB suggested, add using A::name; in class B:

struct A { int name; };
template<typename T> struct C : T { using T::name; };

struct B : private A { 
using A::name; 
friend struct C<B>;
};

your initial example didn't work cause class A is private to B and class C<B> is friend of B but when you access member name from object of C<B> , line using T::name; creates problem since the class B doesn't has any member name in it. it's scope search which find the member name when you try to access it via object of class B

Edit :

Adding using A::name to B takes care of the problem, but publishes the A::name member to everyone, whereas it should only be visible to a particular template instantiation, namely C

if that's the case , then simply declare statement using A::name; in private section in class B i.e

struct B : private A {
protected: using A::name; 
public:
friend struct C<B>;
};
Mr.Anubis
  • 5,132
  • 6
  • 29
  • 44
  • the funny thing is when you try a simplified example without templates (e.g. a class C, deriving from B, which derives privately from A with member name, then both gcc and VC++ complain about `using B::name` in C - of course, because name is not member of B... but why gcc doesn't complain in OP's example is a riddle to me, VC++'s behaviour is correct in my eyes. – codeling Sep 06 '12 at 08:03
  • @nyarlathotep gcc has bug in this I'd say though above example works in gcc – Mr.Anubis Sep 06 '12 at 08:06
  • Why not use `protected: using A::name;`? That would solve my problems completely and keep the intended isolation level. – Nick Sep 06 '12 at 08:25
2

There seems to be a fundamental difference in visibility considerations between gcc and VC++ when using member using-declarations; check this simplified example without templates:

struct A { int name; };
struct B: private A { friend struct C; };
struct C: B {using B::name; };

int main()
{
   C o;
   o.name = 0;
}

It will compile on gcc but not on VC++ (with basically the same error as in the question). Will have to consult the standard on who is doing it right...

codeling
  • 11,056
  • 4
  • 42
  • 71
  • Did you take the `friend struct C` line into account? – Nick Sep 06 '12 at 08:18
  • @Nick: Does that line change anything? I don't think it does; see my comment on the question. C will still be friend to B (which doesn't have any members), not to A (which it would need in order to get access to `A::name`). But feel free to convince me otherwise ;) – codeling Sep 06 '12 at 08:19
  • That line enables GCC to compile. – Nick Sep 06 '12 at 08:22
  • Ah yes, VC++ probably has stricter name resolution rules when it comes to `using`, since my simplified example above also won't compile in VC++, while it does in gcc. – codeling Sep 06 '12 at 08:38