Search code examples
c++c++11decltypeaccess-specifier

Getting around access specifiers with C++0x decltype


Consider the following code:

class A
{
private:
    class B {};
public:
    B f();
};

A a;

A::B g()
{
    return a.f();
}

The compiler rejects this - g cannot return A::B because A::B is private.

But suppose I now use decltype to specify the return value of g:

class A
{
private:
    class B {};
public:
    B f();
};

A a;

decltype(a.f()) g()
{
    return a.f();
}

All of a sudden it compiles fine (with g++ >= 4.4).

So I've basically used decltype to get around an access specifier in a way I would not have been able to in C++98.

Is this intentional? Is this good practice?


Solution

  • Access only applies to names (and as a special case, to constructors/destructors). It doesn't apply to entities themselves. The spec further elaborates

    [ Note: because access control applies to names, if access control is applied to a typedef name, only the accessibility of the typedef name itself is considered. The accessibility of the entity referred to by the typedef is not considered. For example,

    class A {
      class B { };
    public:
      typedef B BB;
    };
    
    void f() {
      A::BB x; // OK, typedef name A::BB is public
      A::B y; // access error, A::B is private
    }
    

    — end note ]

    So what you have disovered here isn't surprising. You can get hold of the type A::B even in C++03, when taking the address of f by saying &A::f and passing it to a function template deducing the return type.