Why does this code compile and lib::Foo::SecretStruct::SecretFunc can be accessed despite SecretStruct being private?
#include <iostream>
#include <memory>
#include <type_traits>
namespace lib {
template <typename T> struct Bar {};
struct Foo {
private:
struct SecretStruct {
static void SecretFunc() {
std::cout << "super secret function is called\n";
}
};
public:
using TBar = Bar<SecretStruct>;
};
} // namespace lib
template <typename T> struct GetSecretImpl {};
template <typename T>
struct GetSecretImpl<lib::Bar<T>> : std::type_identity<T> {};
int main() {
using SecretT = typename GetSecretImpl<lib::Foo::TBar>::type;
SecretT::SecretFunc();
}
Anything private that becomes a part of a public interface becomes visible to code outside.
Consider the following code:
Since
Inneris the return type of a public member function, it can be used by code outsideOuterdespite itself being a private struct.Your code is more involved but in principle does the same thing:
TBaris part of the public interface.SecretStructis used byTBar, so it also becomes a part of the public interface.In C++, the access modifiers only control access to names. This means you cannot use the names
Outer::Inner(in my example) orlib::Foo::SecretStructdirectly from outside the scope they are declared in. In those cases, name lookup is performed first to identify the entity being accessed, then the found entity is checked with access rules.If there are others ways to access an entity indirectly without spelling out its partial or fully qualified name, access modifiers can't stop them.