Question

I was mucking about in some old library code, with the basic objective of refactoring it. This old code does not exactly comply to best practices and beauty (yes - friends are bad, and it has been removed after discovering the below - as it was an oversight in the refactoring).

Now preparing to run some unit tests I compiled the code with clang++, g++, and vc++ (2005 - yes I know it's old, but for backward compatibility - I have to).

g++ and clang++ compiled and ran without errors, but Visual C++ was complaining, so after looking at the code, i found something to the effect of this:

#include <iostream>

class one {

  private:
    struct private_impl;
    private_impl* pimpl_;

  public:
    one();
    ~one();
    void say_hello();
};

class two {

  private:
    friend class one;
    void say_world();

  public:

};

struct one::private_impl {
  two t;
  void say_world();
};

void one::private_impl::say_world() {
   std::cout << " ";
   t.say_world();  //This should not work should it?
}

one::one() : pimpl_(new private_impl) { }

one::~one() {
  delete pimpl_;
}

void one::say_hello() {
  std::cout << "Hello";
  pimpl_->say_world();
  std::cout << std::endl;
}

void two::say_world() {
  std::cout << "World";
}

int main() {
  one test;
  test.say_hello();
  return 0;
}

Compiled with switches (g++ and clang++):

-Wall -Wextra -pedantic

clang++ version: 3.3
g++ version:     4.8.2

Now Visual C++ complains that private_impl::say_world() cannot access the private member of the class two. To me after looking over the c++ friend rules, this is correct - but is my understanding of this wrong? Am I misreading the information (English is not my first language)?

From the standard (c++03 - do not have c++11 at hand where I'm at now):

The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed. The members of an enclosing class have no special access to members of a nested class; the usual access rules (clause 11) shall be obeyed.

And also this:

Friendship is neither inherited nor transitive.

So my basic question here - who is actually correct - clang and gcc or vc++?

Also - this question is just for curiosity about the matter, and trying to understand the world a little better.

Was it helpful?

Solution

The accessibility of member of the surrounding class is affected by CWG 45. That means, at least part of the issue has been classified as a defect in the C++98 Standard. (It seems a resolution has been proposed in 2001, so I don't quite understand why it hasn't been fixed in C++03.)

In C++11, the resolution is incorporated, so the paragraph has changed to [class.access.nest]/1:

A nested class is a member and as such has the same access rights as any other member. The members of an enclosing class have no special access to members of a nested class; the usual access rules shall be obeyed. [Example:

class E {
    int x;
    class B { };

    class I {
        B b;                     // OK: E::I can access E::B
        int y;
        void f(E* p, int i) {
            p->x = i;            // OK: E::I can access E::x
        }
    };

    int g(I* p) {
        return p->y;             // error: I::y is private
    }
};

end example]

(Some) proposed resolutions to defects are implemented in the compilers; note g++ for example specifically says the -std=c++03 flag means

The 1998 ISO C++ standard plus the 2003 technical corrigendum and some additional defect reports.

So it's not obvious what you get when using this flag. However, DRs are "an indication of the intent of the committee", so they can be seen as "bugs" in the Standard, which should be fixed.


VC++2005 seems not to implement the proposed resolution, following the original Standard.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top