-
Notifications
You must be signed in to change notification settings - Fork 760
feat: implementation of gsl::dyn_array #1228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ See [GSL: Guidelines support library](https://isocpp.github.io/CppCoreGuidelines | |
| - [`<algorithms>`](#user-content-H-algorithms) | ||
| - [`<assert>`](#user-content-H-assert) | ||
| - [`<byte>`](#user-content-H-byte) | ||
| - [`<dyn_array>`](#user-content-H-dyn_array) | ||
| - [`<gsl>`](#user-content-H-gsl) | ||
| - [`<narrow>`](#user-content-H-narrow) | ||
| - [`<pointers>`](#user-content-H-pointers) | ||
|
|
@@ -155,6 +156,10 @@ constexpr byte to_byte() noexcept; | |
|
|
||
| Convert the given value `I` to a `byte`. The template requires `I` to be in the valid range 0..255 for a `gsl::byte`. | ||
|
|
||
| ## <a name="H-dyn_array" />`<dyn_array>` | ||
|
|
||
| # TODO (@carsonradtke) | ||
|
|
||
|
Comment on lines
+159
to
+162
|
||
| ## <a name="H-gsl" />`<gsl>` | ||
|
|
||
| This header is a convenience header that includes all other [GSL headers](#user-content-H). | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,352 @@ | ||||||||||||||
| // -*- C++ -*- | ||||||||||||||
| /////////////////////////////////////////////////////////////////////////////// | ||||||||||||||
| // | ||||||||||||||
| // Copyright (c) 2026 Microsoft Corporation. All rights reserved. | ||||||||||||||
| // | ||||||||||||||
| // This code is licensed under the MIT License (MIT). | ||||||||||||||
| // | ||||||||||||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||||||||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||||||||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||||||||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||||||||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||||||||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||||||||||
| // THE SOFTWARE. | ||||||||||||||
| // | ||||||||||||||
| /////////////////////////////////////////////////////////////////////////////// | ||||||||||||||
|
|
||||||||||||||
| #ifndef GSL_DYN_ARRAY_H | ||||||||||||||
| #define GSL_DYN_ARRAY_H | ||||||||||||||
|
|
||||||||||||||
| #include "./assert" | ||||||||||||||
| #include "./narrow" | ||||||||||||||
| #include "./util" | ||||||||||||||
|
|
||||||||||||||
| #include <algorithm> | ||||||||||||||
| #include <iterator> | ||||||||||||||
| #include <memory> | ||||||||||||||
|
|
||||||||||||||
| #ifdef GSL_HAS_RANGES | ||||||||||||||
| #include <ranges> | ||||||||||||||
| #endif /* GSL_HAS_RANGES */ | ||||||||||||||
|
|
||||||||||||||
| namespace gsl | ||||||||||||||
| { | ||||||||||||||
| namespace details | ||||||||||||||
| { | ||||||||||||||
| template <typename T> | ||||||||||||||
| struct dyn_array_traits | ||||||||||||||
| { | ||||||||||||||
| using value_type = T; | ||||||||||||||
| using pointer = T*; | ||||||||||||||
| using reference = T&; | ||||||||||||||
| using const_reference = const T&; | ||||||||||||||
| using difference_type = std::ptrdiff_t; | ||||||||||||||
| using size_type = decltype(sizeof(0)); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this better than the shorter
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't need a #include. But now we already have it for ptrdiff_t, so I'll update it. |
||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| template <typename T, typename Allocator = std::allocator<T>> | ||||||||||||||
| class dyn_array_base : public Allocator | ||||||||||||||
| { | ||||||||||||||
| using pointer = typename dyn_array_traits<T>::pointer; | ||||||||||||||
| using size_type = typename dyn_array_traits<T>::size_type; | ||||||||||||||
|
|
||||||||||||||
| const class dyn_array_impl | ||||||||||||||
| { | ||||||||||||||
| public: | ||||||||||||||
| constexpr dyn_array_impl(pointer data, size_type count) : _data{data}, _count{count} | ||||||||||||||
| { | ||||||||||||||
| Ensures((_count == 0 && _data == nullptr) || (_count > 0 && _data != nullptr)); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto data() const { return _data; } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto count() const { return _count; } | ||||||||||||||
|
|
||||||||||||||
| private: | ||||||||||||||
| pointer _data; | ||||||||||||||
| size_type _count; | ||||||||||||||
| } _impl; | ||||||||||||||
|
|
||||||||||||||
| public: | ||||||||||||||
| constexpr dyn_array_base(const Allocator& alloc) : Allocator{alloc}, _impl{nullptr, 0} {} | ||||||||||||||
| constexpr dyn_array_base(size_type count, const Allocator& alloc) | ||||||||||||||
| : Allocator{alloc}, _impl{count == 0 ? nullptr : Allocator::allocate(count), count} | ||||||||||||||
| {} | ||||||||||||||
|
|
||||||||||||||
| GSL_CONSTEXPR_SINCE_CPP20 ~dyn_array_base() | ||||||||||||||
| { | ||||||||||||||
| if (impl().data()) Allocator::deallocate(impl().data(), impl().count()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto impl() const -> const dyn_array_impl& { return _impl; } | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| template <typename T> | ||||||||||||||
| class dyn_array_iterator | ||||||||||||||
| { | ||||||||||||||
| using size_type = typename dyn_array_traits<T>::size_type; | ||||||||||||||
|
|
||||||||||||||
| public: | ||||||||||||||
| using difference_type = typename dyn_array_traits<T>::difference_type; | ||||||||||||||
| using value_type = typename dyn_array_traits<T>::value_type; | ||||||||||||||
| using pointer = typename dyn_array_traits<T>::pointer; | ||||||||||||||
| using reference = typename dyn_array_traits<T>::reference; | ||||||||||||||
| using const_reference = typename dyn_array_traits<T>::const_reference; | ||||||||||||||
| using iterator_category = std::random_access_iterator_tag; | ||||||||||||||
|
|
||||||||||||||
| #ifdef GSL_HAS_RANGES | ||||||||||||||
| constexpr dyn_array_iterator() : dyn_array_iterator(nullptr, 0, 0) {} | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
or even better |
||||||||||||||
| #endif /* GSL_HAS_RANGES */ | ||||||||||||||
|
|
||||||||||||||
| constexpr dyn_array_iterator(pointer ptr, size_type pos, size_type end_pos) | ||||||||||||||
| : _ptr{ptr}, _pos{pos}, _end_pos{end_pos} | ||||||||||||||
| { | ||||||||||||||
| Ensures((_ptr != nullptr && _end_pos > 0) || (_ptr == nullptr && _end_pos == 0)); | ||||||||||||||
| Ensures(_pos <= _end_pos); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| #if defined(_MSC_VER) && defined(GSL_HAS_RANGES) | ||||||||||||||
| // TODO (@carsonradtke): Investigate why this is necessary for MSVC. | ||||||||||||||
| // Is it a a bug in GSL? STL? MSVC? | ||||||||||||||
| constexpr operator pointer() const { return _ptr + gsl::narrow<size_type>(_pos); } | ||||||||||||||
| #endif /* defined(_MSC_VER) && defined(GSL_HAS_RANGES) */ | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator==(const dyn_array_iterator& other) const | ||||||||||||||
| { | ||||||||||||||
| Expects(_ptr == other._ptr); | ||||||||||||||
| Expects(_end_pos == other._end_pos); | ||||||||||||||
| return _pos == other._pos; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator!=(const dyn_array_iterator& other) const | ||||||||||||||
| { | ||||||||||||||
| return !(*this == other); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator*() const -> reference | ||||||||||||||
| { | ||||||||||||||
| Expects(_ptr != nullptr); | ||||||||||||||
| Expects(_pos < _end_pos); | ||||||||||||||
| return _ptr[_pos]; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator++() -> dyn_array_iterator& | ||||||||||||||
| { | ||||||||||||||
| Expects(_pos < _end_pos); | ||||||||||||||
| _pos++; | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Compare Enforcement in https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#p9-dont-waste-time-or-space |
||||||||||||||
| return *this; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator++(int) | ||||||||||||||
| { | ||||||||||||||
| auto rv = *this; | ||||||||||||||
| ++(*this); | ||||||||||||||
| return rv; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator--() -> dyn_array_iterator& | ||||||||||||||
| { | ||||||||||||||
| Expects(_pos > 0); | ||||||||||||||
| _pos--; | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Compare Enforcement in https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#p9-dont-waste-time-or-space |
||||||||||||||
| return *this; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator--(int) | ||||||||||||||
| { | ||||||||||||||
| auto rv = *this; | ||||||||||||||
| --(*this); | ||||||||||||||
| return rv; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator+=(difference_type diff) -> dyn_array_iterator& | ||||||||||||||
| { | ||||||||||||||
| auto pos = gsl::narrow<difference_type>(_pos); | ||||||||||||||
| Expects(pos + diff <= gsl::narrow<difference_type>(_end_pos)); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||
| _pos = gsl::narrow<size_type>(pos + diff); | ||||||||||||||
| return *this; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator-=(difference_type diff) -> dyn_array_iterator& | ||||||||||||||
| { | ||||||||||||||
| auto pos = gsl::narrow<difference_type>(_pos); | ||||||||||||||
| Expects(pos >= diff); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to above.
|
||||||||||||||
| _pos = gsl::narrow<size_type>(pos - diff); | ||||||||||||||
| return *this; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator+(difference_type diff) const | ||||||||||||||
| { | ||||||||||||||
| return dyn_array_iterator{_ptr, _pos + gsl::narrow<size_type>(diff), _end_pos}; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator-(difference_type diff) const | ||||||||||||||
| { | ||||||||||||||
| return dyn_array_iterator{_ptr, _pos + gsl::narrow<size_type>(diff), _end_pos}; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator-(const dyn_array_iterator& other) const | ||||||||||||||
| { | ||||||||||||||
| Expects(_ptr == other._ptr); | ||||||||||||||
| Expects(_end_pos == other._end_pos); | ||||||||||||||
| return gsl::narrow<difference_type>(_pos) - gsl::narrow<difference_type>(other._pos); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator[](size_type pos) -> reference | ||||||||||||||
| { | ||||||||||||||
| Expects(_pos + pos < _end_pos); | ||||||||||||||
| return _ptr[_pos + pos]; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator[](size_type pos) const -> const_reference | ||||||||||||||
| { | ||||||||||||||
| return const_cast<dyn_array_iterator&>(*this).operator[](pos); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this triggers C26492 and should be |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| private: | ||||||||||||||
| pointer _ptr; | ||||||||||||||
| size_type _pos; | ||||||||||||||
| size_type _end_pos; | ||||||||||||||
|
Comment on lines
+207
to
+209
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| }; | ||||||||||||||
| } // namespace details | ||||||||||||||
|
|
||||||||||||||
| template <typename T, typename Allocator = std::allocator<T>> | ||||||||||||||
| class dyn_array : public details::dyn_array_base<T, Allocator> | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This exposes the base stuff to the clients and the base class publicly inherits from |
||||||||||||||
| { | ||||||||||||||
| using base = details::dyn_array_base<T, Allocator>; | ||||||||||||||
| using pointer = typename details::dyn_array_traits<T>::pointer; | ||||||||||||||
|
|
||||||||||||||
| public: | ||||||||||||||
| using value_type = typename details::dyn_array_traits<T>::value_type; | ||||||||||||||
| using reference = typename details::dyn_array_traits<T>::reference; | ||||||||||||||
| using const_reference = typename details::dyn_array_traits<T>::const_reference; | ||||||||||||||
| using iterator = details::dyn_array_iterator<T>; | ||||||||||||||
| using const_iterator = details::dyn_array_iterator<const T>; | ||||||||||||||
| using reverse_iterator = std::reverse_iterator<iterator>; | ||||||||||||||
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; | ||||||||||||||
| using difference_type = typename details::dyn_array_traits<T>::difference_type; | ||||||||||||||
| using size_type = typename details::dyn_array_traits<T>::size_type; | ||||||||||||||
|
|
||||||||||||||
| using allocator_type = Allocator; | ||||||||||||||
|
|
||||||||||||||
| explicit constexpr dyn_array(const Allocator& alloc = {}) : base{alloc} {} | ||||||||||||||
|
|
||||||||||||||
| explicit constexpr dyn_array(size_type count, const T& value, const Allocator& alloc = {}) | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This ctor takes at least two params, so |
||||||||||||||
| : base{count, alloc} | ||||||||||||||
| { | ||||||||||||||
| std::fill(begin(), end(), value); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UB. The base class called the allocator but did not construct any object. So you cannot call gemini says someone should call Maybe a test with a class can be added for test coverage? |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| GSL_TYPE_IS_ITERATOR(InputIt) | ||||||||||||||
| constexpr dyn_array(InputIt first, InputIt last, const Allocator& alloc = {}) | ||||||||||||||
| : base{gsl::narrow<size_type>(std::distance(first, last)), alloc} | ||||||||||||||
| { | ||||||||||||||
| std::copy(first, last, begin()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| #ifdef GSL_HAS_CONTAINER_RANGES | ||||||||||||||
| template <typename InputRg> | ||||||||||||||
| requires(std::ranges::input_range<InputRg>) | ||||||||||||||
| constexpr dyn_array(std::from_range_t, InputRg&& rg, const Allocator& alloc = {}) | ||||||||||||||
| : base{gsl::narrow<size_type>(std::size(rg)), alloc} | ||||||||||||||
| { | ||||||||||||||
| std::ranges::copy(rg, std::ranges::begin(*this)); | ||||||||||||||
| } | ||||||||||||||
| #endif /* GSL_HAS_RANGES */ | ||||||||||||||
|
|
||||||||||||||
| constexpr explicit dyn_array(size_type count, const Allocator& alloc = {}) | ||||||||||||||
| : dyn_array{count, T{}, alloc} | ||||||||||||||
| {} | ||||||||||||||
|
|
||||||||||||||
| constexpr dyn_array(const dyn_array& other, const Allocator& alloc = {}) | ||||||||||||||
| : dyn_array(other.begin(), other.end(), alloc) | ||||||||||||||
| {} | ||||||||||||||
|
|
||||||||||||||
| constexpr dyn_array(std::initializer_list<T> init, const Allocator& alloc = {}) | ||||||||||||||
| : dyn_array(init.begin(), init.end(), alloc) | ||||||||||||||
| {} | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator=(const dyn_array& other) -> dyn_array& { return dyn_array{other}; } | ||||||||||||||
|
|
||||||||||||||
| constexpr dyn_array(dyn_array&&) = delete; | ||||||||||||||
| dyn_array& operator=(dyn_array&&) = delete; | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator==(const dyn_array& other) const | ||||||||||||||
| { | ||||||||||||||
| return size() == other.size() && std::equal(begin(), end(), other.begin(), other.end()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator!=(const dyn_array& other) const { return !(*this == other); } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto size() const { return impl().count(); } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto empty() const { return size() == 0; } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto max_size() const { return static_cast<size_type>(-1); } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto get_allocator() -> Allocator& { return *this; } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator[](size_type pos) -> reference | ||||||||||||||
| { | ||||||||||||||
| Expects(pos < size()); | ||||||||||||||
| return data()[pos]; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto operator[](size_type pos) const -> const_reference | ||||||||||||||
| { | ||||||||||||||
| return const_cast<dyn_array&>(*this)[pos]; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto data() { return impl().data(); } | ||||||||||||||
| constexpr auto data() const -> const T* { return const_cast<dyn_array&>(*this).data(); } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto begin() { return iterator{data(), 0, size()}; } | ||||||||||||||
| constexpr auto begin() const { return const_iterator{data(), 0, size()}; } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto rbegin() { return reverse_iterator{end()}; } | ||||||||||||||
| constexpr auto rbegin() const { return const_reverse_iterator{end()}; } | ||||||||||||||
|
|
||||||||||||||
| #ifdef _MSC_VER | ||||||||||||||
| constexpr auto _Unchecked_begin() { return data(); } | ||||||||||||||
| constexpr auto _Unchecked_begin() const -> const pointer | ||||||||||||||
| { | ||||||||||||||
| return const_cast<dyn_array&>(*this)._Unchecked_begin(); | ||||||||||||||
| } | ||||||||||||||
| #endif /* _MSC_VER */ | ||||||||||||||
|
|
||||||||||||||
| constexpr auto end() { return iterator{data(), size(), size()}; } | ||||||||||||||
| constexpr auto end() const { return const_iterator{data(), size(), size()}; } | ||||||||||||||
|
|
||||||||||||||
| constexpr auto rend() { return reverse_iterator{begin()}; } | ||||||||||||||
| constexpr auto rend() const { return const_reverse_iterator{begin()}; } | ||||||||||||||
|
|
||||||||||||||
| #ifdef _MSC_VER | ||||||||||||||
| constexpr auto _Unchecked_end() { return data() + size(); } | ||||||||||||||
| constexpr auto _Unchecked_end() const -> const pointer | ||||||||||||||
| { | ||||||||||||||
| return const_cast<dyn_array&>(*this)._Unchecked_end(); | ||||||||||||||
| } | ||||||||||||||
| #endif /* MSC_VER */ | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||
|
|
||||||||||||||
| private: | ||||||||||||||
| constexpr auto impl() const { return base::impl(); } | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? What is the benefit of adding this function? Isn't it sufficient that the base class exposes the function? If the intention is to make |
||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| #ifdef GSL_HAS_DEDUCTION_GUIDES | ||||||||||||||
|
|
||||||||||||||
| template <class InputIt, | ||||||||||||||
| class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>> | ||||||||||||||
| dyn_array(InputIt, InputIt, | ||||||||||||||
| Alloc = {}) -> dyn_array<typename std::iterator_traits<InputIt>::value_type, Alloc>; | ||||||||||||||
|
|
||||||||||||||
| #ifdef GSL_HAS_CONTAINER_RANGES | ||||||||||||||
| template <std::ranges::input_range InputRg, | ||||||||||||||
| class Alloc = std::allocator<std::ranges::range_value_t<InputRg>>> | ||||||||||||||
| dyn_array(std::from_range_t, InputRg&&, | ||||||||||||||
| Alloc = {}) -> dyn_array<std::ranges::range_value_t<InputRg>, Alloc>; | ||||||||||||||
| #endif /* GSL_HAS_RANGES */ | ||||||||||||||
|
|
||||||||||||||
| #endif /* GSL_HAS_DEDUCTION_GUIDES */ | ||||||||||||||
| } // namespace gsl | ||||||||||||||
|
|
||||||||||||||
| #endif /* defined(GSL_DYN_ARRAY_H) */ | ||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.