tags:

views:

107

answers:

5

I am trying to befriend a class in order for it to be able to reach a private constructor of it.

In some_file.h

class B;    

namespace some_name {
class A {
  public:
    A() {}
  private:
    A (int x) {}
    friend class ::B;
};
}

In other_file.h

#include "some_file"

namespace {
class B {
  protected:
    A* get_a(int x) { return new A(x); }
};   
}

When compiling this code, I get - error: 'some_name::A::A(int)' is private.

I now, it is private, this is why I befriended B. What am I doing wrong here? Can't you befriend your constructor? Is there a namespace issue?

Thanks

+9  A: 

Doing this:

namespace {
class B {
  protected:
    A* get_a(int x) { return new A(x) };
}   
}

You're not putting B in the root (global) namespace but in an anonymous one.

So B can't be reached by ::B.

If you want B to be in the root (global) namespace, just don't enclose it with namespace at all. This should do the trick.

ereOn
ok, but if I have no control over the location of B and it has to be an anonymous namespace, how can I still make it work?
izex
@izex: The role of this anonymous namespace is precisely to forbid references to this type outside of the anonymous namespace. Unless you move `A` declaration into the same anonymous namespace there is no way.
ereOn
That makes perfect sense. Thanks.
izex
@izex: I can see at your profile that you didn't accept any answer to your questions yet. If an answer satisfies your needs, don't forget to accept it. And welcome to SO !
ereOn
@ereOn that's wrong. The "anonymous namespace" effect here is completely defeated by the fact it's in a header. Any implementation file that #includes the header statically links the contents of that namespace to itself, thus gaining the anonymous namespace's contents. That is to say, you _can_ access `B`, just say `B` and not `::B`.
wilhelmtell
+1  A: 

You only forward declared and friended a class B in the global namespace. Not a class B in a namespace whatever. You need to fully qualify the name of B.

Edit: Thanks ereOn.
I made a slight mistake. It's true that the reason that you've got a problem is because you've mis-declared and mis-referred-to B, but my original statement wasn't quite true. You need to take B out of the anonymous namespace - it's pointless being in a header anyway.

DeadMG
The name of `B` was already fully qualified (`::B`) but I guess the OP just meant that an empty namespace was resulting to the global namespace.
ereOn
A: 

Additionally to the namespace problem, you forgot several semicolons, namely after the classes A and B and in the function B::get_a.

bitmask
A: 

The problem is that you refer to B as ::B instead of B. Meaning, you're telling the compiler that B is a global name, but in fact it isn't: it's inside an anonymous namespace. You don't have to remove the anonymous namespace, it's just that it may not do what you expect it to do. Because the anonymous namespace is in a header it means what's inside that namespace is linked statically to any implementation file that includes the header. That's not very useful, because you hide nothing. You might as well remove that anonymous namespace.

wilhelmtell
A: 

Can't you befriend your constructor?

You can as shown below

struct B{
    B();
    void f();
};

struct A{
    friend B::B();
private:
    A(){}
};

B::B(){A a;}       // fine

void B::f(){A a;}  // error

int main(){
}
Chubsdad