Почему конструктор std::span не ограничивает элементы при построении с двумя указателями/итераторами

#include <iostream>
#include <span>
#include <string>
#include <string_view>
#include <vector>

namespace {
template <typename TSpan>
auto createSubSpan1(TSpan &, typename TSpan::iterator start,
                    typename TSpan::iterator stop) {
    static_assert(!std::is_convertible_v<typename TSpan::iterator, std::size_t>);
    return TSpan{start, stop};
}

template <typename TSpan>
auto createSubSpan2(TSpan &span, typename TSpan::iterator start,
                    typename TSpan::iterator stop) {
    auto startOffset = std::distance(span.begin(), start);
    auto stopOffset = std::distance(span.begin(), stop);
    std::cout << startOffset << "-" << stopOffset << std::endl;
    static_assert(!std::is_convertible_v<decltype(span.data() + startOffset), std::size_t>);
    return TSpan{span.data() + startOffset, span.data() + stopOffset};
}

template <typename TSpan>
auto createSubSpan3(TSpan &span, typename TSpan::iterator start,
                    typename TSpan::iterator stop) {
    return span.subspan(static_cast<size_t>(std::distance(span.begin(), start)),
                        static_cast<size_t>(std::distance(start, stop)));
}

template <typename TSpan>
auto printSpan(std::string_view header, TSpan span) {
    std::cout << header << std::endl;
    for (const auto &element : span) std::cout << "\t" << element << std::endl;
}
}  // namespace

int main() {
    int a[]{0, 1, 2, 3, 4, 5, 6, 7, 8};
    auto span = std::span{a};

    std::vector<int> vector{11, 12, 13};

    auto beginIt = span.begin();
    auto endIt = std::move(vector.begin(), vector.end(), beginIt);

    printSpan("incorrect (iterator)", createSubSpan1(span, beginIt, endIt));
    printSpan("incorrect (pointer)", createSubSpan2(span, beginIt, endIt));
    printSpan("correct", createSubSpan3(span, beginIt, endIt));
}


Код в компиляторе-проводнике

В этом коде я ожидаю, что методы createSubSpan1/2 вызовут конструктор (3) https://en.cppreference.com/w/cpp/container/span/span

template< class It, class End >
explicit(extent != std::dynamic_extent)
constexpr span( It first, End last );

Однако по какой-то причине они оба печатают полный диапазон вместо трех элементов, которые я ожидал. Вариант 3, вызывающий метод subspan, дает ожидаемый результат.

Вывод кода с GCC, Clang и Clang+libc++:

incorrect (iterator)
    11
    12
    13
    3
    4
    5
    6
    7
    8
0-3
incorrect (pointer)
    11
    12
    13
    3
    4
    5
    6
    7
    8
correct
    11
    12
    13

Итак, из всего, что я могу сделать, следует выбрать упомянутый конструктор и дать мне ожидаемый эффект. Можете ли вы объяснить, почему это не так?

Связанные вопросы:

Короче говоря, вы нарушаете это правило в первых двух случаях: eel.is/c++draft/span.cons#8.1 (extent равно 9, а last-first равно 3).

Daniel Langr 22.02.2023 08:31
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
Уроки CSS 6
Уроки CSS 6
Здравствуйте дорогие читатели, я Ферди Сефа Дюзгюн, сегодня мы продолжим с вами уроки css. Сегодня мы снова продолжим с так называемых классов.
Что такое Css? Для чего он используется?
Что такое Css? Для чего он используется?
CSS, или "Каскадные таблицы стилей", - это язык стилей, используемый в веб-страницах. CSS является одним из основных инструментов веб-разработки...
4
1
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем примере тип переменной span — span<int, 9>, поэтому для createSubSpan1/2() TSpan будет выведен как span<int, 9>, что гарантирует, что возвращаемый диапазон имеет 9 элементов. Другими словами, вы должны убедиться, что stop - start точно равно 9, иначе вы получите UB ([span.cons#8]).

Что касается createSubSpan3(), поскольку subspan() возвращает span<int, dynamic_extent>, количество элементов построенного промежутка равно stop - start.

K, поэтому, если бы a был бы std::vector, этой проблемы не возникло бы. Ни один из методов не использует std::span iso TSpan.

JVApen 22.02.2023 08:34

Звучит как поток проектирования в std::span, который даже позволяет указать размер, если не используется dynamic_extend. Спасибо за ответ, я не понимал, что использую фиксированный размер.

JVApen 22.02.2023 08:48

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