Ответ 1
Какой канонический способ получить std:: array, лежащий в основе raw (C) массив?
Невозможно получить базовый массив C.
Кроме того, есть ли веская причина, почему data() возвращает необработанный указатель, а не ссылка на базовый необработанный массив, или это просто надзор?
В обратном порядке: для std::array
нет достаточной причины для предоставления базового массива C. Как вы уже сказали, массив C будет полезен (по необработанному указателю) только с функциями, получающими ссылку на C-массивы.
Когда в последний раз у вас была функция:
void foo(int (&arr)[5])
Me? Никогда. Я никогда не видел функцию с параметром ссылки на массив C, за исключением получения размера массива (и отклонения указателей):
template <class T, std::size_t N>
auto safe_array_size(T (&)[N]) { return N; }
Давайте немного погрузиться в то, почему ссылки на массивы не используются.
Для начала, из указателя области C с отдельным параметром размера был единственным способом передачи массивов вокруг, из-за распада массива на указатель и отсутствия ссылочного типа.
В С++ существуют альтернативы массивам C, например std::vector
и std::array
. Но даже если у вас есть (устаревший) массив C, у вас есть 2 ситуации:
- если вы передаете его функции C, у вас нет опции ссылки, поэтому вы привязаны к указателю + размер
- когда вы хотите передать его функции С++, идиоматический способ С++ - передать указатели begin + end.
Прежде всего, итераторы begin + end являются универсальными, он принимает любые типы контейнеров. Но не редкость видеть ссылку на std::vector
, когда вы хотите избежать шаблонов, так почему бы не ссылаться на массив C, если у вас есть? Из-за большого недостатка: вы должны знать размер массива:
void foo(int (&arr)[5])
что является чрезвычайно ограничивающим.
Чтобы обойти это, вам нужно сделать его шаблоном:
template <std::size N>
void foo(int (&arr)[N])
который преследует цель избежать шаблонов, поэтому вам лучше пойти с итераторами шаблона begin + end.
В некоторых случаях (например, математические вычисления только на 2 или 3 значениях, которые имеют одна и та же семантика, поэтому они не должны быть отдельными параметрами) a требуется конкретный размер массива и создание функции generic не имеет смысла. В этих случаях задается размер массива гарантирует безопасность, поскольку позволяет передавать только массив из правильный размер во время компиляции; поэтому он выгоден и не является "большой недостаток"
Одна из красавиц (C и) С++ - это огромный диапазон применимости. Так что да, вы всегда найдете некоторые поля, которые используют или нуждаются в уникальной уникальной функции уникальным образом. Сказав это, даже в вашем примере я все равно уклоняюсь от массивов. Когда у вас есть фиксированное количество значений, которые не должны быть семантически разделены, я думаю, что структура будет правильным выбором по массивам большую часть времени (например, glm::mat4
вместо float[4]
).
Но не стоит забывать, что такое std::array
: современная замена C-массивов. Одна вещь, которую я узнал при анализе вариантов, заключается в том, что нет абсолютного "лучше, чем". Всегда есть "зависит". Но не в этом случае: std::array
должна однозначно заменить C массивы в интерфейсах. Поэтому в редком случае, когда в качестве эталонного параметра необходим контейнер с фиксированным размером, не имеет смысла активизировать использование массивов C, когда у вас уже есть std::array
. Таким образом, единственным допустимым случаем, когда подвергать лежащий в основе массив C массива std::array
, является потребность в некоторых старых библиотеках, у которых есть ссылочные параметры массива C. Но я думаю, что в большей картине, добавляющей это к интерфейсу, это не оправдано. Новый код должен использовать struct (btw std::tuple
становится проще и проще в использовании по каждому стандарту) или std::array
.