Given a class like this:
class MyClass {
struct PrivateType {};
public:
static void func(PrivateType) {}
};
I can't do this because PrivateType is private:
MyClass::func(MyClass::PrivateType());
But I can do this:
MyClass::func({});
So I'm instantiating a private type, what looks like, outside of the class scope. Is that an implicit conversion from an initializer list? If so, when a parameter is implicitly converted, does the conversion take place in scope of the class i.e. as if it was part of the body of the function? Why is that and is that always the case?
CodePudding user response:
{}
is a syntax called braced-init-list. It doesn't have a type or value category and doesn't represent any object or value like an expression does. It therefore also doesn't really make sense to consider something like a conversion from a {}
to exist.
There are specific rules separate from those for expressions as arguments on how overload resolution considers _braced-init-list_s as arguments.
There are also rules separate from those for initialization from parentheses when initializing from a braced-init-list. However, after overload resolution, the function parameter is always initialized simply as if the argument was the initializer for the parameter in a copy-initialization, meaning that the PrivateType
parameter object, which I will name here private_type
, will be initialized as if by
PrivateType private_type = {};
in a local variable definition. However, this initialization always happens in the context of the caller. All of this is true for expressions as function arguments as well.
The initialization with the type as defined in your example would resolve to aggregate initialization, because PrivateType
is an aggregate class. Since there are no members or base classes to initialize, the initialization then doesn't do anything.
None of this considers whether PrivateType
is accessible (private
) from the context of the caller, because accessibility only applies when deciding whether a member can be named (where e.g. overload resolution to a member function, constructor or operator overload counts as named). You are never using the name PrivateType
in the caller though. private
does not prevent construction of a member class in any context.