Found this strange compilation behavior, checked on VS2012, VS2017 and https://www.onlinegdb.com/online_c++_compiler)
Basically for private nested classes you can call public functions outside, but not public constructors.
3 questions:
what is the reasoning behind compiler letting me call func()?
if compiler lets me call func(), why I cannot call ctor?
if I cannot call ctor, how come emplace_back is able to do it?
class Outer {
struct PrivateInner {
PrivateInner() {}
void func() {}
};
public:
PrivateInner inner;
std::vector<PrivateInner> innerVect;
};
void f1()
{
Outer c;
c.inner.func(); // COMPILING, but why?
}
void f2()
{
Outer c;
c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?
c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?
}
As I see I still can create a (static) function createObject():
class Outer {
struct PrivateInner {
PrivateInner() {}
static PrivateInner createObject() { return PrivateInner(); }
void func() {}
};
.....
};
and then call it.
createObject() may be non-static if calling static from instances is not pure standard thing.
c.innerVect.push_back(c.inner.createObject()); // COMPILING
to "hack" compilation
Note that the nested struct
PrivateInner
is declared as private
, so only Outer::PrivateInner
is private
, you can't use this name to declare variable like Outer::PrivateInner pi;
without sufficient access right, but you can write it like decltype(Outer::inner) pi;
.
On the other hand, its constructor and member function are public
, so they can be called.
c.inner.func(); // COMPILING, but why?
func()
is public
, so if you have got an instance of type Outer::PrivateInner
you can call func
on it.
c.innerVect.push_back(Outer::PrivateInner()); // NOT COMPILING, why no access to ctor if there is access to func()?
It has nothing to do with the constructor, you just can't use the name Outer::PrivateInner
here.
c.innerVect.emplace_back(); // COMPILING, but why? Doesn't it call Outer::PrivateInner inside?
The constructor is public
, then it could be used to construct the object. std::vector
doesn't use the name like Outer::PrivateInner
directly; it uses the name specified as the template argument.
BTW: For the same reason,
c.innerVect.push_back(c.inner.createObject()); // COMPILING
but c.innerVect.push_back(Outer::PrivateInner::createObject());
won't compile.