Почему нет перегрузки std::data() для std::valarray?

C++11 представил std::begin(std::valarray&), а также std::end(std::valarray&).

C++17 представил std::data(), который работает с std::vector, std::array, C-стилем. массивы и т.д. Но почему не был введен перегруженный std::data() для std::valarray?

std::valarray указывается как непрерывное хранилище, доступ к которому можно получить, взяв адрес a[0] (см. Примечания).

std::data(std::valarray& a) можно было просто определить для возврата &(a[0]). Почему это не сделано? Это оплошность?

Моя мотивация заключается в том, что я работаю над универсальной библиотекой сериализации. Когда он получает непрерывные массивы двоичных чисел из источника (например, CBOR), он определяет, есть ли в целевом контейнере перегруженная функция data(container), функция-член container.resize(n), а также соответствующий value_type (соответствующий примитивный числовой тип). Существование всех трех позволяет эффективно memcpy() переносить исходные данные непосредственно в целевой контейнер. Если бы была перегрузка std::data(std::valarray&), моя жизнь упростилась бы. Его отсутствие не мешает, но делает код более запутанным.


ДОПОЛНЕНИЕ. Причина, по которой я хочу обнаружить функцию data, заключается в том, что она сообщает мне, что целевой контейнер непрерывен. Если он непрерывен, то я могу сделать эффективную копию байта (через std::memcpy или std::copy не имеет большого значения). Если он не является непрерывным, то мне нужно распаковать каждый невыровненный номер исходного массива по одному и добавить его в целевой контейнер, используя push_back, emplace и т. д. в зависимости от типа контейнера.


ДОБАВЛЕНИЕ 2. Я решил использовать подход с адаптером и признаками вместо обнаружения наличия функции data. Это упростит поддержку нестандартных или определяемых пользователем типов контейнеров. Мой вопрос о том, почему нет std::data(std::valarray& a), остается в силе.


ДОБАВЛЕНИЕ 3: я должен был уточнить, что мне нужно сделать этот хакерский прием для типизированных массивов CBOR, которые могут быть только числами. Более того, числа в исходном буфере не выровнены по границам элементов. Я знаю, что для двоичных данных может потребоваться перестановка байтов по порядку байтов, и что копирование байтов в тип с плавающей запятой может вызвать странное поведение NaN, если с ним не обращаться осторожно.

Теперь я сожалею, что упомянул о своей мотивации, и должен был оставить вопрос std::data(std::valarray& a) сам по себе. В какое крушение превратился этот вопрос, ха-ха. :-)


person Emile Cormier    schedule 06.02.2021    source источник
comment
Существование обоих позволяет эффективно memcpy() передавать исходные данные непосредственно в целевой контейнер. Есть ли причина, по которой вы не используете std::copy()/std::copy_n() для этой цели, позволяя компилятору оптимизировать их до memcpy когда возможно? Вам не нужен доступ к data() для каждого контейнера, чтобы использовать std::copy/_n, только итераторы.   -  person Remy Lebeau    schedule 06.02.2021
comment
@RemyLebeau Я не могу использовать std::copy, потому что исходные данные находятся в буфере необработанных байтов, и нет гарантии, что они будут выровнены по границам элементов. Типизированные массивы CBOR, полученные в сетевом буфере, — это источник данных, если вы действительно хотите знать кровавые подробности.   -  person Emile Cormier    schedule 06.02.2021
comment
Я думаю, что std::valarray на самом деле не считается частью STL, так как не соответствует философии STL.   -  person Galik    schedule 06.02.2021
comment
@EmileCormier Если вы можете копировать данные с помощью необработанных указателей, вы можете копировать с помощью итераторов. Указатели являются допустимыми итераторами. std::copy() с итераторами произвольного доступа, такими как векторные массивы и массивы C, оптимизируется в код, эквивалентный memcpy. Код типа container.resize(n); memcpy(std::data(container), source, n * sizeof(decltype(container)::value_type)); можно переписать как container.resize(n); std::copy(source, source+n, std::begin(container)); или container.resize(n); std::copy_n(source, n, std::begin(container));   -  person Remy Lebeau    schedule 06.02.2021
comment
@Galik Да, я использовал этот тег так же, как многие используют STL для обозначения стандартной библиотеки. Виноват. Я удалю тег.   -  person Emile Cormier    schedule 06.02.2021
comment
@remy берет буфер из 32-битных данных int, которые не выровнены по 4 байтам. Допустимо memcpy эти байты в буфер из 32-байтовых целых чисел, но недопустимо формировать указатель типа int на невыровненный буфер и копировать их стандартным способом. OTOH, размещение непрочитанных байтов IEEE с неправильным порядком байтов в числах с плавающей запятой может привести к значениям жесткой ловушки.   -  person Yakk - Adam Nevraumont    schedule 06.02.2021
comment
@RemyLebeau: невозможно std::copy перейти от середины std::vector<uint8_t> к std::vector<float>, где std::vector<uint8_t> — сетевой буфер, а std::vector<float> — тип назначения. Сетевой буфер содержит метаданные до того, как начнутся фактические данные массива с плавающей точкой, и не гарантируется, что данные массива с плавающей запятой будут выровнены по границе float. По техническим причинам, в которые я не хочу вдаваться, я не могу получать метаданные отдельно перед получением полезной нагрузки в буфер с выравниванием по плавающей запятой.   -  person Emile Cormier    schedule 06.02.2021
comment
@Yakk-AdamNevraumont OTOH, помещение неразобранных байтов IEEE с неверным порядком байтов в числа с плавающей запятой может привести к значениям жесткой ловушки. Верно. Я задал этот вопрос о том, как лучше всего справиться с этим: stackoverflow.com/q/65910802/245265   -  person Emile Cormier    schedule 06.02.2021
comment
@Galik есть некоторая путаница из-за того, как обычно используется STL. В чем разница между «STL» и «Стандартной библиотекой C++»?   -  person Mark Ransom    schedule 06.02.2021
comment
valarrays не упоминаются в N4017 , исходное предложение.   -  person 1201ProgramAlarm    schedule 06.02.2021
comment
@ 1201ProgramAlarm: За исключением каких-либо технических причин, по которым не может быть std::data(std::valarray&), это, вероятно, самый простой ответ.   -  person Emile Cormier    schedule 06.02.2021
comment
@MarkRansom Конечно, дезинформации много. Но STL всегда правильно использовалось для обозначения контейнера и алгоритмов частей стандартной библиотеки. Первоначальный автор STL (Степанов), создатель C++ (Страуструп) и все крупные авторы C++ (Мейерс, Саттер и т. д.) используют этот термин именно так.   -  person Galik    schedule 06.02.2021
comment
Я придумал обходной путь для моего варианта использования. Я могу просто определить функцию data(std::valarray&) (и ее вариант const) в пространстве имен моей библиотеки. Выполнив using std::data; заранее, логика десериализации через ADL найдет пользовательскую функцию data для std::valarray в дополнение к перегруженным функциям std::data для других контейнеров.   -  person Emile Cormier    schedule 06.02.2021
comment
@EmileCormier Невозможно std::copy из середины std::vector<uint8_t> в std::vector<float> - конечно, можно, например: std::vector<uint8_t> buffer; /* fill buffer ... */ std::vector<float> values(n); std::copy_n(reinterpret_cast<char*>(&buffer[index]), n * sizeof(float), reinterpret_cast<char*>(values.data()));   -  person Remy Lebeau    schedule 06.02.2021
comment
@RemyLebeau Да, конечно, ты прав, когда так говоришь. Я думал, вы имели в виду каламбур от uint8_t до float, а затем выполнение copy_n с использованием указателей float*. Я был озадачен, почему кто-то с такой высокой репутацией предложил такое, хе-хе.   -  person Emile Cormier    schedule 06.02.2021
comment
@EmileCormier У меня возник соблазн преобразовать uint8_t* в float* и скопировать float, но, как говорилось ранее, это было бы незаконно. Тем не менее, использование каламбура через char допустимо для целей копирования байтов.   -  person Remy Lebeau    schedule 06.02.2021
comment
@RemyLebeau: Чтобы ответить на ваш первоначальный вопрос: просто я предпочитаю std::memcpy при копировании необработанных байтов из личного стиля. Я не думаю, что стилистический выбор относится к вопросу, почему std::valarray не имеет функции data. Я уверен, что вопрос о std::memcpy и std::copy при работе с байтами уже задавался здесь много раз, и я проконсультируюсь с ними, чтобы пересмотреть свой стиль использования std::memcpy.   -  person Emile Cormier    schedule 06.02.2021
comment
@RemyLebeau: Кроме того, причина, по которой я хочу обнаружить функцию data, заключается в том, что она сообщает мне, что контейнер назначения является непрерывным. Если он непрерывен, то я могу сделать эффективную копию байта (через std::memcpy или std::copy не имеет большого значения). Если он не является непрерывным, мне нужно распаковать каждое значение массива по одному и добавить его в целевой контейнер.   -  person Emile Cormier    schedule 06.02.2021
comment
@EmileCormier Если он не является непрерывным, то я должен распаковывать каждое значение массива по одному и добавлять его в целевой контейнер - для этого тоже можно использовать std::copy/_n()   -  person Remy Lebeau    schedule 06.02.2021
comment
@RemyLebeau: для этого потребуется временный буфер с выравниванием по элементам, и я не хочу навязывать для этого затраты памяти пользователям библиотеки сериализации.   -  person Emile Cormier    schedule 06.02.2021
comment
Тот факт, что контейнер имеет функцию data, не говорит всего, что вам нужно знать о возможности безопасного использования memcpy. Он не будет работать должным образом со многими классами и подвержен ошибкам. Следует добавить множество других ограничений, например, тип не должен иметь определяемый пользователем деструктор и т. д. В прошлом такие типы были POD (обычные старые данные). С недавними стандартами есть гораздо больше различий.   -  person Phil1970    schedule 06.02.2021
comment
Было бы гораздо безопаснее, не зная всех деталей стандарта, сначала переместить исходные данные, чтобы они были правильно выровнены, а затем использовать std::copy. Кроме того, копирование данных из сети очень хрупкое, так как вам нужно знать, среди прочего, об индийскости, формате с плавающей запятой и целочисленном размере. Как только вы примете во внимание все это, оптимизация копирования может не иметь большого значения, если ваши данные не содержат большие массивы заданного типа, которые не требуют преобразования. Для общей библиотеки сериализации я серьезно сомневаюсь, что надлежащие условия будут часто выполняться.   -  person Phil1970    schedule 06.02.2021
comment
И, кстати, в 2021 году 99,999% обмена данными должно осуществляться либо в формате XML, либо в формате JSON, которые намного проще обрабатывать на многих языках и понятны человеку. Тот факт, что одна ошибка в библиотеке сериализации может привести к повреждению данных, является огромным преимуществом для удобочитаемых данных, поскольку человек может исправить данные без особых знаний.   -  person Phil1970    schedule 06.02.2021
comment
@Phil1970: Приведите один пример, когда data() в совместимом со стандартом контейнере стандартной библиотеки нельзя использовать в качестве места назначения для операции memcpy. Если вы посмотрите на большую таблицу внизу en.cppreference.com/w/cpp/container вы увидите, что его поддерживают только vector и array (а также string), и они гарантированно сохраняют данные непрерывно, начиная с C++11. Я хорошо разбираюсь в форматах с порядком байтов и с плавающей запятой; это не первое мое родео. Наконец, я не спросил о том, какой формат сериализации мне следует использовать.   -  person Emile Cormier    schedule 06.02.2021
comment
@ Phil1970 Не то, чтобы это имело значение для этого вопроса, но библиотека сериализации, над которой я работаю, поддерживает JSON в дополнение к CBOR и может быть расширена для любого JSON-подобного кодека. Пользователь сам решает, предпочитает ли он производительность удобочитаемости. При работе с большими числовыми массивами тесты показывают, что CBOR почти на порядок быстрее (что неудивительно).   -  person Emile Cormier    schedule 06.02.2021
comment
@EmileCormier data() нельзя использовать на std::vector<std::string>>. Тот факт, что данные непрерывны, не гарантирует, что использование memcpy безопасно. Любой тип, который содержит ресурс, подсчитывает количество экземпляров или имеет какой-либо побочный эффект в конструкторе копирования, не должен копироваться путем копирования байтов.   -  person Phil1970    schedule 06.02.2021
comment
Почему бы не использовать существующую библиотеку CBOR. Кажется, их много! Уже слишком большой выбор!   -  person Phil1970    schedule 06.02.2021
comment
@Phil1970 Phil1970 В дополнение к обнаружению существования data я также проверяю, что value_type целевого контейнера является примитивным числовым типом, соответствующим исходному. Поэтому я бы не стал пытаться десериализовать типизированный массив чисел в vector<string> — это было бы глупо. :-) Что касается того, почему бы не использовать существующую библиотеку, я проверил существующие, и ни одна из них не ставит все галочки в моем списке желаний. Я думаю, что смогу придумать что-нибудь получше (надеюсь). Если бы каждый автор библиотеки, обращающийся сюда за помощью, прислушивался к совету не заморачиваться, то инноваций больше не было бы.   -  person Emile Cormier    schedule 06.02.2021
comment
@Phil1970: Я должен был уточнить, что мне нужно выполнить этот взлом только для типизированных массивов CBOR, которые могут содержать только числа. Извините, что не разъяснил это в первую очередь.   -  person Emile Cormier    schedule 06.02.2021
comment
@MooingDuck Почему valarray такой медленный?. Но std::data не поддерживает его не из-за того, что он медленный.   -  person phuclv    schedule 08.02.2021


Ответы (1)


Как указано в комментариях 1201ProgramAlarm, предложение add std::data не упоминает std::valarray. Если кто-то не может указать, почему &(a[0]) нельзя использовать для получения указателя данных valarray, простой ответ состоит в том, что valarray либо забыто, либо проигнорировано в предложении.

person Community    schedule 06.02.2021