0 is a null pointer constant
S.4.9:
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to
zero.
A null pointer constant can be converted to any other pointer type:
S.4.9:
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that
type
What you gave for the definition of A
is considered an aggregate:
S.8.5.1:
An aggregate is an array or a class with no user-declared constructors, no private or protected
non-static data members, no base classes, and no virtual functions.
You are specifying an initializer clause:
S.8.5.1:
When an aggregate is initialized the initializer can contain an initializer-clause consisting of a brace enclosed,
comma-separated list of initializer-clauses for the members of the aggregate
A
contains a member of the aggregate of type std::string
, and the initializer clause applies to it.
Your aggregate is copy-initialized
When an aggregate (whether class or array) contains members of class type and is initialized by a brace enclosed
initializer-list, each such member is copy-initialized.
Copy initializing means that you have the equivalent to std::string s = 0
or std::string s = 42
;
S.8.5-12
The initialization that occurs in argument passing, function return, throwing an exception (15.1), handling
an exception (15.3), and brace-enclosed initializer lists (8.5.1) is called copy-initialization and is equivalent
to the form T x = a;
std::string s = 42
will not compile because there is no implicit conversion, std::string s = 0
will compile (because an implicit conversion exists) but results in undefined behavior.
std::string
's constructor for const char*
is not defined as explicit
which means you can do this: std::string s = 0
Just to show that things are actually being copy-initialized, you could do this simple test:
class mystring
{
public:
explicit mystring(const char* p){}
};
struct A {
mystring s;
};
int main()
{
//Won't compile because no implicit conversion exists from const char*
//But simply take off explicit above and everything compiles fine.
A a = {0};
return 0;
}