Почему структура aggreggate может быть инициализирована скобками, но не может быть использована с использованием того же списка аргументов, что и при инициализации скобок?

Кажется, что этот код:

#include <string>
#include <vector>

struct bla
{
    std::string a;
    int b;
};

int main()
{
    std::vector<bla> v;
    v.emplace_back("string", 42);
}

можно заставить работать должным образом в этом случае, но это не так (и я понимаю, почему). дающий bla конструктор решает это, но удаляет совокупность типов, что может иметь далеко идущие последствия.

Это упущение в Стандарте? Или я пропускаю определенные случаи, когда это взрывается у меня на лице, или это просто не так полезно, как я думаю?

2 ответа

Это упущение в Стандарте?

Это считается открытым дефектом в стандарте, обозначаемом как LWG # 2089. Но хорошее решение этого неуловимо.

Фундаментальная проблема заключается в том, что вы не можете использовать волевые списки в скобках. Инициализация списков типов с помощью конструкторов может фактически скрывать конструкторы, так что некоторые конструкторы могут быть недоступны для вызова посредством инициализации списка. Это vector<int> v{1, 2}; проблема. Это создает 2-элемент vector, а не 1-элементный вектор, чей единственный элемент равен 2.

Из-за этого вы не можете использовать инициализацию списка в общих контекстах, таких как allocator::construct,

Что приводит нас к:

Я бы подумал, что для этого нужно сделать трюк SFINAE, иначе прибегнуть к скобке init, которая также работает для агрегатов.

Это потребует is_aggregate тип черта. Которого в настоящее время не существует, и никто не предложил его существования. О, конечно, вы могли бы обойтись с is_constructible, как говорится в предлагаемом решении вопроса. Но есть проблема с этим: он эффективно создает альтернативу инициализации списка.

Считают, что vector<int> пример из ранее. {1, 2} интерпретируется как двухэлементный initializer_list, Но через emplace, это будет интерпретироваться как вызов двухцелого конструктора, так как is_constructible из этих двух элементов будет правдой. И это вызывает эту проблему:

vector<vector<float>> fvec;
fvec.emplace(1.0f, 2.0f);
vector<vector<int>> ivec;
ivec.emplace(1, 2);

Они делают две совершенно разные вещи. в fvec случай, он выполняет инициализацию списка, потому что vector<float> не конструируется из двух поплавков. в ivec случай, он вызывает конструктор, потому что vector<int> конструируется из двух целых чисел.

Так что вам нужно ограничить инициализацию списка в allocator::construct работать только если T это совокупность.

И даже если вы это сделаете, вам придется распространять этот трюк SFINAE во всех местах, где используется косвенная инициализация. Это включает any/variant/optional"s in_place конструкторы и огневые точки, make_shared/unique звонки и т. д., ни один из которых не использует allocator::construct,

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

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

23.2.1 / 15.5

T является EmplaceConstructible в X из аргументов, для аргументов ноль или более аргументов означает, что следующее выражение корректно сформировано:

allocator_traits<A>::construct(m, p, args)

23.2.1 / 15

[Примечание: контейнер вызывает allocator_traits<A>::construct(m, p, args) построить элемент в р, используя аргументы. Конструкция по умолчанию в std::allocator позвоню ::new((void*)p) T(args), но специализированные распределители могут выбрать другое определение. —Конечная записка]

Таким образом, по умолчанию распределитель использует конструктор, изменение этого поведения может привести к потере обратной совместимости. Вы можете прочитать больше в этом ответе /questions/45182887/pochemu-emplaceback-ne-ispolzuet-ravnomernuyu-initsializatsiyu/45182907#45182907.

Также есть проблема "На пути к более совершенной пересылке" и случайная дискуссия о ее будущем.

Другие вопросы по тегам