как преобразовать std::array‹char, N› в char (&dest)[N]?

Как передать std::array<char, N> такой функции:

template<size_t N>
void safe_func(char (&dest)[N]);

?

Я пробую это:

#include <array>

template <size_t N> using SafeArray = char[N];

template <size_t N> void safe_func(char (&dest)[N]) {}

int main() {
  SafeArray<10> a1;
  safe_func(a1);
  std::array<char, 10> a2;
  safe_func(*static_cast<SafeArray<10> *>(static_cast<void *>(a2.data())));
}

Это работает, но я сомневаюсь, может быть что-то не так с моим приведением, и на другом компиляторе или платформе (я использовал gcc/linux/amd64) я столкнулся с неправильной ссылкой?


person user1244932    schedule 19.07.2018    source источник
comment
Я не вижу этого нарушения, но вы можете прочитать это: заголовок stackoverflow.com/questions/41463005/   -  person NathanOliver    schedule 19.07.2018
comment
вы можете просто переинтерпретировать ссылку: она будет короче и менее подвержена ошибкам. Но опять же, такое программирование опасно. Если типы элементов и размеры типов не совпадают, вы этого не заметите, но вред будет нанесен.   -  person Red.Wave    schedule 19.07.2018


Ответы (1)


В одну сторону:

template<class T, size_t N>
using c_array = T[N];

template<class T, size_t N>
c_array<T, N>& as_c_array(std::array<T, N>& a) {
    return reinterpret_cast<T(&)[N]>(*a.data());
}

int main() {
    std::array<int, 2> a;
    int(&b)[2] = as_c_array(a);
}

Стандарт требует, чтобы std::array был агрегатом, а его единственным членом является T[N], указатель, к которому возвращается std::array::data(). Поскольку адрес агрегата совпадает с адресом его первого члена, вызов и разыменование std::array::data() не являются строго необходимыми, reinterpret_cast<T(&)[N]>(a) тоже работает.

std::array появился в boost, где его единственной целью было предоставить стандартный интерфейс контейнера (begin/end/size/empty/etc.) для встроенных массивов T[N] и ничего больше, чтобы не было никаких накладных расходов и абстракции с нулевой стоимостью. Следовательно, вы можете в основном приводить boost::array<T, N> и T[N] туда и обратно, хотя, возможно, нарушая правила псевдонимов, делая это (компилятор предполагает, что boost::array<T, N> и T[N] относятся к разным объектам, поэтому вам нужно знать, как справиться с этим в вашем конкретном случае).

Стандарт отбросил все обоснования и выразил требования std::array в очень слабых и расплывчатых выражениях. Так что люди задаются вопросом, действительно ли там только T[N] член, а не какой-то якобы внеземной тип, который удовлетворяет требованию.

person Maxim Egorushkin    schedule 19.07.2018
comment
Небольшая придирка: где стандарт говорит, что std::array содержит T[N]? - person geza; 19.07.2018
comment
@geza Стандарт говорит, что это агрегат и непрерывное хранилище для нескольких элементов. Ничто не подходит под это описание, кроме T[N]. - person Maxim Egorushkin; 19.07.2018
comment
Конечно, но я не нашел в стандарте, что std::array содержит T[N]. Это может быть что угодно, не только обычные доступные типы (например, NULL не определено, что это такое). Но это всего лишь придирки, так как std::array наверняка реализовано как T[N], иначе нет смысла. - person geza; 19.07.2018
comment
@geza В своем первом комментарии я объяснил, почему, учитывая стандартные требования, это не может быть ничего, кроме T[N]. Вы можете указать другой тип, который удовлетворяет требованиям для поддержки вашего утверждения это может быть что угодно. - person Maxim Egorushkin; 20.07.2018
comment
Мне нравится, как этот ответ резюмирует буквально все об истории и MO C++ одним махом, а также отвечает на вопрос как с практической, так и с юридической точки зрения. Высшие оценки :D - person Lightness Races in Orbit; 20.07.2018
comment
@MaximEgorushkin: Технически он может рекурсивно содержать другие структуры, которые сами по себе [в конечном итоге] обертывают T[N] и ничего больше, без заполнения. Но тогда это фактически одно и то же. Так что я не знаю, почему я написал этот комментарий - person Lightness Races in Orbit; 20.07.2018
comment
@LightnessRacesinOrbit Да, я думал о array<N> : array<N-1>. Но почему? - person Maxim Egorushkin; 20.07.2018
comment
@LightnessRacesinOrbit T[0] имеет неправильный формат, а array<0> — правильный. - person Maxim Egorushkin; 20.07.2018
comment
@MaximEgorushkin: меня всегда забавляло, что T[0] неправильно сформировано, а new T[0] правильно, но опять же, меня легко позабавить - person Lightness Races in Orbit; 20.07.2018