Переадресация на месте строительства и инициализация списка

Под пересылкой на месте строительства, я понимаю станд :: Распределитель :: конструкт и различные методы emplace, например, станд :: вектор :: emplace_back. Я просто обнаружил, что перенаправленная конструкция на месте в C ++ не (не может?) Использовать синтаксис инициализации списка. В результате кажется, что никогда нельзя пересылать на месте конструкцию агрегата. Я просто хочу убедиться, что перенаправленная конструкция на месте не поддерживает инициализацию списка и, следовательно, агрегированные типы. Это связано с ограниченностью языка? Может ли кто-нибудь предоставить ссылку на стандарт по этому вопросу? Ниже приводится иллюстрация:

В то время как мы можем сделать строительство на месте непосредственно

int(*p)[3] = ...;
new(p) int[3]{1, 2, 3};

мы не можем сделать пересылку на месте строительства, как

std::allocator<int[3]> allo;
allo.construct(p, 1, 2, 3);

1

Решение

В то время как {} был назван единым синтаксисом инициализации, он далеко не универсален.

возьмите эти два примера:

size_t a = 3;
size_t b = 1;
std::vector<size_t> v1{a,b};
std::vector<size_t> v2(a,b);

в первом случае мы строим вектор, содержащий два элемента, 3 а также 1,

Во втором случае мы создаем вектор, содержащий 1,1,1 — 3 копии 1,

живой пример.

Так {} основанная конструкция может вызвать другое поведение, чем () на основе строительства в некоторых случаях. Более того, в приведенном выше случае нет способа достичь синтаксиса «3 копии из 1», используя {} строительство (что я знаю). Но {3,2} регистр можно обработать, просто явно создав список инициализаторов и передав его (),

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

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

Теоретически, list_emplace методы, которые конструируют с использованием {} вместо этого можно добавить к каждому интерфейсу. Я призываю вас сделать это!

5

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

std::allocator«s construct() (а также реализация по умолчанию, предоставляемая std::allocator_traits) указано использовать (): ::new((void *)p) U(std::forward<Args>(args)...) (см. [allocator.members] / p12, [allocator.traits.members] / p5).

Нецелесообразно менять его на {} на данный момент, потому что он будет молча сломать существующий код:

std::vector<std::vector<int>> foo;
foo.emplace_back(10, 10); // add a vector of ten 10s with (); two 10s with {}

Есть вопрос LWG чтобы заставить его вернуться к использованию {} если () не работает Посмотрим, согласен ли комитет с этим направлением.

@Yakk указывает на потенциальные недостатки этого подхода:

foo.emplace_back(10); // ten 0s
foo.emplace_back(10, 10); // ten 10s
foo.emplace_back(10, 10, 10); // three(!) 10s

Аналогичная проблема (см. Приложение B N2215) привело к решению, что инициализация списка всегда будет предпочтительнее initializer_list Конструкторы.

3

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