To see what's really going on, declare copy and move constructors, compile in C++14 mode or earlier, and disable copy elision.
Coliru link
Output:
default ctor
move ctor
In the first snippet, the compiler looks for constructors of X that take a single argument, since you've provided a single argument. These are the copy and move constructor, X::X(const X&) and X::X(X&&), which the compiler will implicitly declare for you if you do not declare them yourself. The compiler then converts {} to an X object using the default constructor, and passes that X object to the move constructor. (You must use fno-elide-constructors to see this otherwise the compiler will elide the move, and in C++17 copy elision became mandatory.)
In the second snippet, the compiler now has a choice of converting {} to X (then calling the move constructor), or converting {} to std::initializer_list<int> (then calling the initializer list constructor). According to [over.ics.list]/6.2, the conversion from {} to X, which calls the default constructor, is a user-defined conversion, while according to [over.ics.list]/4, the conversion from {} to std::initializer_list<int> is the identity conversion. The identity conversion is better than a user-defined conversion, so the compiler calls the initializer list constructor.