Как преобразовать массив C в std :: initializer_list? - PullRequest
1 голос
/ 22 октября 2019

Я знаю указатель на массив и его размер. Какой контейнер можно из него создать? Я пытался сделать это:

std::initializer_list<int> foo(arr, arr + size);

Это работает для MSVC, но не для gcc

Ответы [ 3 ]

5 голосов
/ 22 октября 2019

std::initializer_list - это ссылочный тип, предназначенный только для поддержки инициализации списка, и имеет только ctor по умолчанию и неявно copy-ctor. Любой другой ctor является расширением.

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

Стандартный контейнер для использования, если вы не знаете,лучше было бы std::vector. Или вам достаточно простого вида, например std::span?

4 голосов
/ 22 октября 2019

Здесь есть два вопроса, каждый со своим ответом.


Как преобразовать массив C в std :: initializer_list?

Выне может. Это не имеет смысла. std::initializer_list действительно используется только для инициализации (как следует из названия) объектов. Это в основном то, что создается из записи {}, например:

myObject obj = {0,1,2,3,4};

Попытка создать экземпляр std::initializer_list не очень полезна в каком-либо другом смысле, который я могу себе представить, особенноначиная с C ++ 14 невозможно все равно создать во время выполнения , так как он имеет конструктор constexpr.


Если у вас есть какой-то объект foo, который принимает std::initializer_list вот так:

class foo {
    foo(std::initializer_list list) {
        //...
    }
};

И вам интересно, как создать этот объект без std::initializer_list, тогда ответом будет просто добавить еще один конструктор:

class foo {
    // an actual array
    foo(type arr[size]) {
        //...
    }

    // as a pointer
    foo(type arr*, size_t size) {
        //...
    }
};

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


Какой контейнер из него можно создать?

Любой контейнер последовательности ,У большинства из них есть своего рода конструктор, который принимает указатели на объект (фактически, технически он требует итераторов, но указатели в этом контексте будут работать одинаково) или массив. Они в значительной степени предназначены для простого преобразования из массивов Си. Какой из них вы используете, будет зависеть от вашей ситуации.

Кроме того, std::span (который не указан как «контейнер последовательности») был упомянут как возможный контейнер, который может быть созданиз массива C по низкой цене. Хотя я не могу поручиться за них лично, так как я не слишком знаком с готовящимся стандартом.


Заключительное примечание: если MSVC позволяет это, то либо a) вы, возможно, находитесь в C++ 11 (хотя я не могу подтвердить, было ли это разрешено в C ++ 11, просто, что конструктор не constexpr в C ++) или b) это ошибка компилятора в MSVC.

4 голосов
/ 22 октября 2019

Если вам нужен фактический контейнер, владеющий данными, то вам нужен std::vector. Это будет стоить вам копию и распределение. Если все, что вам нужно, это действовать как контейнер, то вам нужно получить std::span из C ++ 20. Он берет указатель и размер и упаковывает его в интерфейс, похожий на массив.

Использование MSVS

std::initializer_list<int> foo(arr, arr + size);

не является стандартным. В соответствии со стандартом единственным конструктором для std::initiliazer_list является

constexpr initializer_list() noexcept;
...