Использование отрицательного индекса массива для доступа к предыдущему члену - PullRequest
0 голосов
/ 15 ноября 2018

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

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

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].

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

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

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

prog.cc:6:33: warning: ISO C++ prohibits anonymous structs [-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 голосов
/ 15 ноября 2018

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

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

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

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

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

...