Почему не установить обратно() использовать равномерное инициализации?



следующий код:



#include <vector>

struct S
{
int x, y;
};

int main()
{
std::vector<S> v;
v.emplace_back(0, 0);
}


дает следующие ошибки при компиляции с GCC:



In file included from c++/4.7.0/i686-pc-linux-gnu/bits/c++allocator.h:34:0,
from c++/4.7.0/bits/allocator.h:48,
from c++/4.7.0/vector:62,
from test.cpp:1:
c++/4.7.0/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = S; _Args = {int, int}; _Tp = S]':
c++/4.7.0/bits/alloc_traits.h:265:4: required from 'static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]'
c++/4.7.0/bits/alloc_traits.h:402:4: required from 'static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = S; _Args = {int, int}; _Alloc = std::allocator<S>]'
c++/4.7.0/bits/vector.tcc:97:6: required from 'void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, int}; _Tp = S; _Alloc = std::allocator<S>]'
test.cpp:11:24: required from here
c++/4.7.0/ext/new_allocator.h:110:4: error: new initializer expression list treated as compound expression [-fpermissive]
c++/4.7.0/ext/new_allocator.h:110:4: error: no matching function for call to 'S::S(int)'
c++/4.7.0/ext/new_allocator.h:110:4: note: candidates are:
test.cpp:3:8: note: S::S()
test.cpp:3:8: note: candidate expects 0 arguments, 1 provided
test.cpp:3:8: note: constexpr S::S(const S&)
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'const S&'
test.cpp:3:8: note: constexpr S::S(S&&)
test.cpp:3:8: note: no known conversion for argument 1 from 'int' to 'S&&'


предполагая, что vector через обычный () синтаксис конструктора для построения элемента из аргументов в emplace_back(). Почему бы и нет vector использовать {} единообразный синтаксис инициализации вместо этого, чтобы сделать примеры, подобные приведенной выше работе?



мне кажется, что нет ничего, чтобы потерять с помощью {} (вызывает конструктор, когда есть один, но все еще работает, когда его нет), и было бы больше в духе C++11 использовать {} - в конце концов, весь смысл униформа инициализация заключается в том, что он используется равномерно, то есть везде - для инициализации объектов.

767   1  

1 ответ:

великие умы думают одинаково; v). Я представил отчет о дефектах и предложил внести изменения в стандарт по этой самой теме.

http://cplusplus.github.com/LWG/lwg-active.html#2089

кроме того, Люк Дантон помог мне понять сложность: прямая vs равномерная инициализация в std:: allocator.

когда EmplaceConstructible (23.2.1 [контейнер.требования.общие]/13) требование используется для инициализации один объект, происходит прямая инициализация. Инициализация агрегата или использование конструктора std:: initializer_list с emplace требует именования инициализированный тип и перемещение временного. Это является результатом std:: allocator:: построить с помощью прямой инициализации, не инициализация списка (иногда называемая " равномерной инициализацией") синтаксис.

изменение std:: allocator:: construct для использования инициализации списка будет ли, среди прочего, отдавать предпочтение std:: initializer_list конструктор перегружается, разбивая допустимый код на неинтуитивный и невозможно исправить способом - не было бы никакой возможности для emplace_back для доступа к конструктор, вытесненный std:: initializer_list без сущности повторно push_back.

std::vector<std::vector<int>> v;
v.emplace_back(3, 4); // v[0] == {4, 4, 4}, not {3, 4} as in list-initialization

предлагаемый компромисс заключается в использовании SFINAE с std:: is_constructible, который проверяет, хорошо ли сформирована прямая инициализация. Если is_constructible-это false, тогда альтернатива std:: allocator:: Construct перегрузка выбирается какой использует список инициализации. Поскольку инициализация списка всегда возвращается прямая инициализация, пользователь будет видеть диагностические сообщения, как если бы список-инициализация (uniform-initialization) всегда использовались, потому что перегрузка прямой инициализации не может завершиться неудачей.

Я вижу два угловых случая, которые открывают пробелы в этой схеме. Один происходит когда аргументы, предназначенные для std:: initializer_list удовлетворяют a конструктор, например попытка emplace-вставить значение {3, 4} в этот приведенный выше пример. Решение: явно указать тип std::initializer_list, как в v. emplace_back(std::initializer_list (3, 4)). Так как это соответствует семантика, как если бы std:: initializer_list были выведены, кажется, что здесь не будет никаких проблем.

другой случай, когда аргументы, предназначенные для агрегатной инициализации удовлетворите конструктор. Поскольку агрегаты не могут быть определены пользователем конструкторы, для этого требуется, чтобы первый нестатический элемент данных агрегат неявно преобразуется из агрегатного типа, и что список инициализаторов имеет один элемент. Решение укажите инициализатор для второго элемента. Его по-прежнему невозможно на месте построить агрегат только с одним нестатическим элементом данных путем преобразование из типа, конвертируемого в собственный тип агрегата. Этот похоже на приемлемо маленькую дырочку.

Comments

    Ничего не найдено.