2

I have faced an interesting dilemma during implementing a custom data structure. Unfortunately I could not found any answer in the C++11 standard, so I hope someone can explain it to me.

There is a class which has a private nested class. Also it uses this private sub-class as a return value in a public function. Like this:

class Enclosing {
private:
    // Private nested class
    struct Nested {
        Nested(int x) : _x(x) {}
        int _x;
    };

    Nested _nested;

public:
    Enclosing():_nested(42) {}

    // Use private nested class in public interface
    const Nested& get_nested() {
        return _nested;
    }
};

If I try to use call get_nested it compiles, although I can not create a local variable of type Enclosing::Nested to store the result. But this is where auto comes to rescue:

int main() {
    Enclosing e;
    //Enclosing::Nested n = e.get_ref( ); //Error! Enclosing::Nested is private
    auto n = e.get_nested( );             //Ok, unless we name a type
    cout << n._x << endl;
}

Even more, with some variadic templates magic I can even call a constructor of the nested class and screate a new exemplar of it:

template<class T, typename... Args>
T* create(const T& t, Args... args) {
    return new T(args...);
}

int main() {
    Enclosing e;
    // We can even create a new instance of the private nested class
    auto np = create(e.get_nested( ), 68); 
    //Enclosing::Nested* np = create(e.get_nested( ), 68); // But don't name a type
    cout << np->_x << endl;
}

Could please anybody explain this behavior to me? Why does auto permit us access to the otherwise private data type? There must be some obvious reason which I just can not see so far. Reference to the paragraph in the Standard is highly welcome.

Thank you very much!

(checked in gcc 4.7.3 and clang 3.2)

Peter Popov
  • 662
  • 1
  • 6
  • 9

1 Answers1

1

Besides the duplicate, which explains it, you can actually improve the intention of the author of the private class by making the members of the inner class private and declaring the outer class as a friend. That way your seconds example (create) won't compile anymore (in practice, add an explicit and hence private copy-ctor as well):

class Nested {
    Nested(int x) : _x(x) {}
    int _x;
    friend class Enclosing;
};

This ensures that all instances of Nested are created from Enclosing.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180