I know a pointer to an array and its size. What container can be created from it? I tried to do this:
std::initializer_list<int> foo(arr, arr + size);
It works for the MSVC, but not for the gcc
std::initializer_list is a reference-type designed just for supporting list-initialization, and only has the default-ctor, and implicitly copy-ctor. Any other ctor is an extension.
What you can do is initializing the target-container directly from an iterator-range, without involving any intermediate views.
The standard container to use unless you know better would be std::vector. Or would using a simple view like std::span be enough for you?
std::span is exactly what I'm looking for. Thank you!If you need an actual data owning container, then what you want is a std::vector. This is going to cost you a copy and an allocation. If all you need is to act like a container, then what you want is the upcoming std::span from C++20. It takes a pointer and a size and wraps it in an interface that is like an array.
MSVS's use of
std::initializer_list<int> foo(arr, arr + size);
is not standard. Per the standard the only constructor for std::initiliazer_list is
constexpr initializer_list() noexcept;
arr, arr + size.span is not a container. The initializer_list was just a means to an end.There are kind of two questions here, each with their own answer.
How to convert C array to std::initializer_list?
You can't. It doesn't really make sense to. std::initializer_list is really only used to initialize (as its name implies) objects. It's basically is what is created from the {} notation like this:
myObject obj = {0,1,2,3,4};
Attempting to create an instance of an std::initializer_list isn't really useful in any other sense that I can think of, especially since C++14 it's impossible to create at runtime anyway, since it has a constexpr constructor.
If you have some object foo that accepts an std::initializer_list, like this:
class foo {
foo(std::initializer_list list) {
//...
}
};
And you are wondering how to create this object without anstd::initializer_list, then the answer is to simply add another constructor:
class foo {
// an actual array
foo(type arr[size]) {
//...
}
// as a pointer
foo(type arr*, size_t size) {
//...
}
};
If you are using a third party library, or some other library you don't control, that does not have another constructor, then chances are it's not intended to be used this way. In that case, I would consult your documentation or vendor.
What container can be created from it?
Any sequence container. Most of them have some sort of constructor that accepts pointers to an object (actually, it technically takes iterators, but pointers will work the same in this context) or an array. They are pretty much designed for easy conversion from C arrays. Which one you use will depend on your situation.
Also, std::span (which is not listed as a "sequence container") has been mentioned as a possible container that can get created from a C array at low cost. Although, I can't vouch for them personally, as I'm not too familiar with the upcoming standard.
Final note: If MSVC allows this, then either a) you're possibly in C++11 (though I can't confirm if this was allowed in C++11 either, just that the constructor is not constexpr in C++) or b) it is a compiler bug in MSVC.
Initializer_listconstructor is really simple:constexpr initializer_list() noexcept;. Ifstd::initializer_list<int> foo(arr, arr + size);works under Visual Studio, it's because they added extensions.initializer_listis designed for use with braced lists of times, it's not a general container. You can usevectororspanamong other optionsstd::vectorand probably ditch the array entirely.std::vectorin the first place? What's the array good for if you're just going to stuff it in a container later anyway?