Использование отрицательного индекса массива для доступа к предыдущему члену

Я хотел бы использовать отрицательный индекс массива для доступа к члену того же типа, который непосредственно предшествует этому массиву в структуре.

Рассмотрим этот тип кода:

union hello {
int a[2];
struct { int b0; int b1[1]; };
};

Я хочу использовать b1[-1] чтобы получить доступ b0,

Когда я пытаюсь это сделать, кажется, что clang и gcc точно понимают, чего я хочу.

extern const int test = hello{{42, 1337}}.b1[-1];

Это правильно определяет во время компиляции, что test действительно 42,

К сожалению, Clang выдает предупреждение, что -1 не связан. Gcc делает тоже, если я изменяю const в constexpr,

Как правильно написать этот тип кода?

Вот способы, которые я уже знаю, но не люблю:

  • использование a[] с индексированием на основе 1.
  • Делать b1 указатель, который указывает на a[1],

0

Решение

Если я правильно понимаю ваш вопрос, у вас есть переменные {c0, с1, с2, с3,…}, а иногда вы хотите рассматривать их как массив [c1, с2, с3,…], в другое время как массив [c0, с1, с2, с3,…].

(Я не уверен, что понимаю Зачем Вы хотите сделать это, но не берите в голову.)

Вот одно из решений:

int A[5];
int *B = A+1;
A[0] = c0;
A[1] = c1;
A[2] = c2;
....

Теперь вы можете перебрать A [i], если хотите включить c0, и над B [I], если вы этого не сделаете.

0

Другие решения

Когда я пытаюсь это сделать, кажется, что clang и gcc точно понимают, чего я хочу

Да, но они также генерируют некоторую диагностику, если их спросить (gcc):

prog.cc:6:33: предупреждение: ISO C ++ запрещает анонимные структуры [-Wpedantic]
struct {int b0; int b1 [1]; };

Кроме того, доступ к b1 который не является активным членом союза (a является инициализированным) является неопределенным поведением.

Вместо этого вы можете написать класс, который инкапсулирует данные и логику требуемого доступа:

#include <iostream>
#include <array>

template<size_t Dim>
class Hello
{
std::array<int, Dim> data_;
public:
template<class... ArgType>
constexpr Hello(ArgType... args) : data_{args...} {};

constexpr int first()       const noexcept { return data_[0]; }

constexpr int one_based(int i) const { return data_.at(i + 1); }
constexpr int zero_based(int i) const { return data_.at(i); }
};

int main()
{
constexpr Hello<2> hi {42, 1337};

static_assert(hi.first() == 42);

static_assert(hi.one_based(-1) == 42);
static_assert(hi.one_based(0) == 1337);

static_assert(hi.zero_based(0) == 42);
static_assert(hi.zero_based(1) == 1337);

std::cout << "So far, so good...\n";
}
0