Авто с равномерной инициализацией расширяется до неожиданного типа

Рассмотрим эту короткую программу, скомпилированную с GCC 4.7.2 g++ -std=c++11 test.cc

#include <memory>
#include <queue>

struct type{
type(int a) : v(a) {}
int v;
};

typedef std::shared_ptr<type> type_ptr;

int main(){
int value = 3;
std::queue<type_ptr> queue;
auto ptr{std::make_shared<type>(value)};
queue.push(ptr);
}

Компилятор выводит следующие ошибки:

src/test.cc: In function ‘int main()’:
src/test.cc:15:17: error: no matching function for call to ‘std::queue<std::shared_ptr<type> >::push(std::initializer_list<std::shared_ptr<type> >&)’
src/test.cc:15:17: note: candidates are:
In file included from /usr/include/c++/4.7/queue:65:0,
from src/test.cc:2:
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note: void std::queue<_Tp, _Sequence>::push(const value_type&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:211:7: note:   no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘const value_type& {aka const std::shared_ptr<type>&}’
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note: void std::queue<_Tp, _Sequence>::push(std::queue<_Tp, _Sequence>::value_type&&) [with _Tp = std::shared_ptr<type>; _Sequence = std::deque<std::shared_ptr<type>, std::allocator<std::shared_ptr<type> > >; std::queue<_Tp, _Sequence>::value_type = std::shared_ptr<type>]
/usr/include/c++/4.7/bits/stl_queue.h:216:7: note:   no known conversion for argument 1 from ‘std::initializer_list<std::shared_ptr<type> >’ to ‘std::queue<std::shared_ptr<type> >::value_type&& {aka std::shared_ptr<type>&&}’

Указывает, что автоматический тип раскрывается в список инициализатора вместо std::shared_ptr<type>; фактически заменяет {...} с = ... делает компиляцию кода при автоматическом расширении до правильного типа.

Я немного удивлен, что этот, казалось бы, очевидный вариант использования не дает ожидаемого результата. Тем более, что я вспоминаю новый синтаксис инициализации скобок, который нужно рекламировать как окончательное решение проблем инициализации.

Итак, мой вопрос: это было задумано в стандарте? Или это недосмотр или даже ошибка в gcc? Или я просто думаю об этом неправильно?

3

Решение

Как говорит Ксео в своем комментарии, это стандартное поведение. 7.1.6.4 авто спецификатор [dcl.spec.auto] пункт 6 определяет:

После того, как тип описатель-идентификатор был определен в соответствии с 8.3, тип объявленной переменной с использованием описатель-идентификатор определяется по типу его инициализатора по правилам вывода аргументов шаблона. Позволять T быть типом, который был определен для идентификатора переменной d, получать P от T заменив вхождения auto либо с новым параметром шаблона изобретенного типа U или, если инициализатор является приготовился-INIT-лист (8.5.4), с std::initializer_list<U>, Тип, выведенный для переменной d затем выводится A определяется с использованием правил вывода аргументов шаблона из вызова функции (14.8.2.1), где P тип параметра шаблона функции и инициализатор для d это соответствующий аргумент. Если
вычет не проходит, декларация не оформлена.

Это также широко презирается — есть предложение находится на рассмотрении комитета изменить поведение для C ++ 14. Поддержка C ++ 14 для обобщенного лямбда-захвата усугубляет проблему.

Обновление: в Урбане (см. CWG Motion 16 в N4251 WG21 2014-11 Урбана Минут) комитет подал заявку N3922 Новые правила автоматического удержания из списка braced-init-list на рабочий документ C ++ 17. Они решили исправить особый случай, который позволяет auto вывести initializer_list добавляя другой особый случай. auto работает так же для копирование списка инициализация, но для прямой список инициализация из приготовился-INIT-лист с одним элементом auto выводит из этого элемента напрямую. прямой список инициализация из многоэлементного приготовился-INIT-лист сейчас плохо сформирован.

Это означает, что с учетом

auto x = {42};

x имеет тип std::initializer_list<int>, но в

auto x{42};

x является int,

9

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]