Почему массив span и конструкторы std::array отличаются от конструкторов контейнеров
Я играл с последней спецификацией для std::span
используя clang trunk и libC++ на Godbolt, и некоторые конструкторы сбивают с толку.
В частности, я нахожу конструкторы из простого старого массива и и std::array
отличаться от других контейнеров.
Например, следующий код появляется для компиляции:
std::vector<int*> v = {nullptr, nullptr};
std::span<const int* const> s{v};
Однако это не так:
std::array<int*, 2> a = {nullptr, nullptr};
std::span<const int* const> s{a};
Похоже, это соответствует описанию конструкторов на cppreference.com, я просто пытаюсь понять, почему это так. Кто-нибудь может пролить свет?
1 ответ
Это похоже на недосмотр. Конструкторы массива в настоящее время определены как:
template<size_t N> constexpr span(array<value_type, N>& arr) noexcept;
template<size_t N> constexpr span(const array<value_type, N>& arr) noexcept;
Но, вероятно, следует указать как:
template<class T, size_t N>
requires std::convertible_to<T(*)[], ElementType(*)[]>
constexpr span(array<T, N>& arr) noexcept;
template<class T, size_t N>
requires std::convertible_to<const T(*)[], ElementType(*)[]>
constexpr span(const array<T, N>& arr) noexcept;
Что сделает ваш пример компиляцией, как это безопасно. Я представил вопрос LWG. Это сейчас LWG 3255.
Формулировка уже имеет это ограничение, указанное в [span.cons] / 11:
template<size_t N> constexpr span(element_type (&arr)[N]) noexcept; template<size_t N> constexpr span(array<value_type, N>& arr) noexcept; template<size_t N> constexpr span(const array<value_type, N>& arr) noexcept;
Ограничения:
extent == dynamic_extent || N == extent
являетсяtrue
, а такжеremove_pointer_t<decltype(data(arr))>(*)[]
конвертируется вElementType(*)[]
,
Таким образом, у нас уже есть правильное ограничение. Это просто data(arr)
на самом деле не зависит ни в одном из этих случаев, поэтому ограничение выполняется тривиально. Нам просто нужно сделать эти шаблоны.