As an addendum to this question, what is going on here:
#include
using namespace std;
struct A {
string s;
};
int main() {
A a = {0}
Your struct is an aggregate, so the ordinary rules for aggregate initialization work for it. The process is described in 8.5.1. Basically the whole 8.5.1 is dedicated to it, so I don't see the reason to copy the whole thing here. The general idea is virtually the same it was in C, just adapted to C++: you take an initializer from the right, you take a member from the left and you initialize the member with that initializer. According to 8.5/12, this shall be a copy-initialization.
When you do
A a = { 0 };
you are basically copy-initializing a.s with 0, i.e. for a.s it is semantically equivalent to
string s = 0;
The above compiles because std::string is convertible from a const char * pointer. (And it is undefined behavior, since null pointer is not a valid argument in this case.)
Your 42 version will not compile for the very same reason the
string s = 42;
will not compile. 42 is not a null pointer constant, and std::string has no means for conversion from int type.
P.S. Just in case: note that the definition of aggregate in C++ is not recursive (as opposed to the definition of POD, for example). std::string is not an aggregate, but it doesn't change anything for your A. A is still an aggregate.