Можно ли как-то заменить макрос

У меня в коде часто встречается ситуация, что к одной и той же переменной нужно обращаться много-много раз.

Предположим, что есть структура

struct S{
  std::vector<size_t> vector_in_s;
};

И еще одна, которая хранит первую

struct V{
  std::vector<S> vector_in_v;
};

Теперь я начинаю это как-то использовать

int main(){
  V str_v;

  str_v.vector_in_v[12].vector_in_s[7] = 0;  // A
  str_v.vector_in_v[11].vector_in_s[3] = 9;  // B
  str_v.vector_in_v[88].vector_in_s[8] = 3;  // C
  
  // auto& A = str_v.vector_in_v[12].vector_in_s[7];
  // auto& B = str_v.vector_in_v[11].vector_in_s[3];
  // auto& C = str_v.vector_in_v[88].vector_in_s[8];
  // Так я сделать не могу, потому что, когда я добавляю что-то в вектор, он может
  // перевыделить память и все ссылки становятся недействительными
  // Приходится каждый раз прописывать полностью, потому что я не могу объявить три ссылки

  if (str_v.vector_in_v[12].vector_in_s[7] != str_v.vector_in_v[11].vector_in_s[3]){
    str_v.vector_in_v[12].vector_in_s[7].emplace_back(33);
    str_v.vector_in_v[11].vector_in_s[3].emplace_back(2);
  }
}

Я нашел решение - макрос

  #define A str_v.vector_in_v[12].vector_in_s[7]
  #define B str_v.vector_in_v[11].vector_in_s[3]
  #define C str_v.vector_in_v[88].vector_in_s[8]
  

Тогда код принимает вид

int main(){
  V str_v;

  #define A str_v.vector_in_v[12].vector_in_s[7]
  #define B str_v.vector_in_v[11].vector_in_s[3]
  #define C str_v.vector_in_v[88].vector_in_s[8]

  if (A != B){
    A.emplace_back(33);
    B.emplace_back(2);
  }

  #undef A
  #undef B
  #undef C
}

Но мне не нравится такая практика; хочется избавиться от макросов и заменить это 'чем-нибудь'


Ответы (4 шт):

Автор решения: HolyBlackCat

Раз ссылка не подходит, тогда лямбда.

auto foo = [&]() -> auto & {return str_v.vector_in_v[12].vector_in_s[7];};
foo().emplace_back(42);
→ Ссылка
Автор решения: Aptem_f

а почему бы не написать функцию

int get(int index_v, int index_s)
{
return str_v.vector_in_v[index_v].vector_in_s[index_s]
}

upd


struct S{
  std::vector<size_t> vector_in_s;
  size_t operator()(int index) { return vector_in_s[index]; }
};


struct V{
  std::vector<S> vector_in_v;
  S operator()(int index) { return vector_in_v[index]; }
};

V str_v;
str_v(12)(7).emplace_back(42);
// Правильность не гарантирую, но смысл вот такой
→ Ссылка
Автор решения: Harry

Вам точно надо именно

struct S{
  std::vector<size_t> vector_in_s;
};

struct V{
  std::vector<S> vector_in_v;
};

а не

vector<vector<size_t>> v;

И все ваши обращения тогда вырождаются в выражения вроде

v[5][10] = 7;

Зачем именно структуры?

→ Ссылка
Автор решения: user7860670

Это можно сделать посредством создания объекта-запроса, инкапсулирующего обращение по индексу. Такой подход также позволит в перспективе добавить удобные методы для реализации дополнительных операций, например для обращения к соседним элементам и т.п.

class
t_Query final
{
    private: ::std::size_t m_outer_index;
    private: ::std::size_t m_inner_index;
    
    public: explicit constexpr
    t_Query(::std::size_t const outer_index, ::std::size_t const inner_index) noexcept
    :   m_outer_index{outer_index}
    ,   m_inner_index{inner_index}
    {
        return;
    }
    
    public: auto &
    operator [](V & container) const noexcept
    {
        return container.vector_in_v[m_outer_index].vector_in_s[m_inner_index];
    }
    
    public: auto const &
    operator [](V const & container) const noexcept
    {
        return container.vector_in_v[m_outer_index].vector_in_s[m_inner_index];
    }
};

int main()
{
    V str_v;
    constexpr t_Query const loca{12, 7};
    constexpr t_Query const locb{11, 3};
    // ...
    loca[str_v] = 3;  
    locb[str_v] = 9;  
    if (loca[str_v] != locb[str_v])
    {
        // ...
    }
    return 0;
}
→ Ссылка