Это вызвано главным образом этим конструктором std::map
:
template< class InputIterator >
map( InputIterator first, InputIterator last,
const Compare& comp = Compare(),
const Allocator& alloc = Allocator() );
Даже если аргументы не являются итераторами, этот конструктор включен, поэтому участвует в разрешении перегрузки. В результате
{1, 2} -> std::map<int, int>
{{1, 2}} -> std::map<int, int>
оба являются действительными преобразованиями, что означает
{{1, 2}} -> Dict
{{1, 2}} -> std::map<int, int>
- оба допустимых преобразования. Следовательно, три конструктора Dict
неоднозначны:
Dict(map<int, int>);
Dict(const Dict&);
Dict(Dict&&);
В случае new Dict({{1, true}})
, InputIterator
не может быть правильно выведен, поэтому двусмысленности больше нет.
Вы можете сделать Dict(map<int, int>);
явным или использовать три пары скобок, предложенных Беном Фойгтом.
Почему работают три пары скоб?
Поскольку в этом случае для кандидата-конструктора копирования / перемещения пользовательские преобразования не допускаются. Это прямо указано в [over.best.ics] / 4 (я не имею отношения к другим частям):
Однако, если целью является
и конструктор или пользовательская функция преобразования являются кандидатами на
... или
вторая фаза [over.match.list] , когда список инициализаторов содержит ровно один элемент, который сам является списком инициализаторов, а цель является первым параметром конструктора класса X, и преобразование в X или ссылку на cv X,
определяемые пользователем последовательности преобразования не учитываются.