In most cases, initialization either requires {} (e.g. you cannot initialize an aggregate with () s) or both {} and () do the same thing (e.g. most class types that aren’t aggregates). That, in itself, seems like a good argument in favor of uniform initialization. The problem case seems like a pretty small subset of the world: those cases in which list-initialization and non-list-initialization (a) both compile and (b) do different things. The canonical example of this phenomenon, and the one that likely appears in every blog and book that introduces list-initialization, comes to us from std::vector :

The reason this happens is that list-initialization for non-aggregate class types happens in two phases: first, we only consider those constructors that take a std::initializer_list and then, only if no viable constructor is found, do we consider the rest. For v , we find a constructor taking a std::initializer_list<int> , which works, so we’re done. It’s not that this is a better match than the constructor taking a size_t and an int const& , it’s that the latter is not even considered as an option. For w , the std::initializer_list constructor isn’t viable, since we’re not list-initializing, so the latter constructor is selected. This strong preference for initializer-list constructors can lead to quite a bit of confusion.

The potentially different behavior for something like initializing a vector<int> might seem like one of those things you just have to memorize to ace your next C++ interview, but it has pretty serious implications for how to write generic code. Consider trying to write a [completely pointless, yet illustrative] function template that just explicitly copies its argument:

Being paranoid of list-initialization in generic code is a good trait to have, especially when the template types can be arbitrary user types. You can’t be sure that’s going to happen.

This difference also now appears in more possible places, thanks to class template argument deduction. Consider the following:

What is the type of w2 ? The intent is probably for it to be a std::vector<int> but it’s actually a std::vector<std::vector<int>::iterator> ! Of course. The reasoning is basically the same as in the first example: the initializer-list constructor is strongly preferred, and is now viable since we’re doing deduction. The initialization of w worked fine despite using the {} s, but one subtle change and that went away. Using () s to initialize w2 would give us the desired deduction of std::vector<int> .