0

I'm making a calculator that can accept more than one operator at once (e.g. 5x5x5). I have a map that contains the positions of the operators, and what type they are (x/+-). I also have a for loop for (auto const& [key, val] : oper_map) which I got from this post.

In order to get the left and right numbers, I need to know where the left and right operators are. I've attempted to use std::prev and std::next with the key like this:

int loper_pos = -1;
int roper_pos = 0;
double lnum;
double rnum;
char loper;
char roper;

//map defined elsewhere
for (auto const& [key, val] : oper_map)
{
    //loper is left operator while roper is right opeprator

    //tracks the position of the loop
    int map_pos = std::distance(oper_map.begin(), oper_map.find(key)); 

    if (map_pos == 0) loper_pos = -1;
    else
    {
        loper_pos = std::prev(key);
        loper = std::prev(val);
    }
    if (map_pos == oper_map.size()) roper_pos = oper_map.size() + 1;
    else
    {
        roper_pos = std::next(key);
        roper = std::next(val);
    }

but I guess it doesn't work since key isn't an iterator? I also can't increment/decrement key or val (or when using the C++11 version in this post), so I guess it doesn't count as an iterator? I don't know iterators confuse me.

This post appears to be what I want but for whatever reason lower_bound() does not work with oper_map; no suitable conversion.

Marek R
  • 32,568
  • 6
  • 55
  • 140
Shidouuu
  • 368
  • 4
  • 14
  • Just change your loop to use an iterator... ? – super Mar 10 '21 at 14:55
  • when you care about the position don't use a range based loop. The purpose of the range based loop is to hide iterators behind an abstraction, but you want iterators – 463035818_is_not_an_ai Mar 10 '21 at 14:56
  • I think a `std::vector>` would be more suitable. (Actually, there is most likely some even more suitable structure, like a syntax tree.) – molbdnilo Mar 10 '21 at 14:57
  • @molbdnilo Huh, well I read somewhere you shouldn't use pairs in a vector when you could use a map, would those values be easier to access? – Shidouuu Mar 10 '21 at 14:59
  • " you shouldn't use pairs in a vector when you could use a map" in this generality the statement is just wrong – 463035818_is_not_an_ai Mar 10 '21 at 15:00
  • 1
    @Shidouuu The word "could" is sneaky. In this context, it pretty much means "if you mostly look up specific keys" - that is, if you treat your vector as a map - not "if it is possible". If you're mostly interested in the sequence of values, e.g. finding the previous or next one, a map is less efficient in both time and space (and simplicity). – molbdnilo Mar 10 '21 at 15:14

1 Answers1

1

No. key is not an iterator.

for (auto const& [key, val] : oper_map)

key is a const reference to the key in the map. If you want iterators, use iterators:

for (auto it = oper_map.begin(); it != oper_map.end(); ++it) {
    auto next = std::next(it);
    auto prev = std::prev(it);
}

However, consider that std::map is not a sequential container. If you are interested in the positions of elements in the container, maybe a std::vector< std::pair<Key,MappedValue>> is more handy.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • So for bidirectional iterators, prev/next operators will traverse the entire container to find out the value? Regarding std::map, it is sequential, in that its values are sorted and ordered. So the implementation next/prev for std::map will require red-black tree traversal, using a comparison function from the root node until the last leaf node? – bigdata2 Dec 02 '22 at 16:04
  • @bigdata2 I dont remember why i mentioned complexity here. It only matter for the overload that takes `n` to get you the n-th next / previous iterator. `std::next` / `std::prev` never have to traverse the enitre container, only for `std::next( oper_map.begin(), oper_map.size())` or `std::prev(oper_map.end(),oper_map.size())` – 463035818_is_not_an_ai Dec 02 '22 at 18:06