0

I would like to access elements of a vector in C++. I have generated the vector using the Boost_variant library since I needed to store both int and string types as inputs.

Now I would like to access elements of the vector by index, and in reverse so that I can implement a condition on them - something of the sort:

for (int i = last_element_of_vector, i >=0, i--){
     if (myvec[i] == 0 && myvec[i-1] == 1){
         *do something*
     }
}

I can only seem to find iterators with loop over the vector and print out the elements without any index i for which the elements may be accessed.

My MWE is as follows:

#include <iostream>                         
#include <sstream>                           
#include <string>                           
#include <vector>                           
#include <boost/filesystem.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/variant.hpp>                

#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <algorithm>

using namespace std;
using namespace boost::adaptors;
using namespace boost::assign;

typedef boost::variant<std::string,int> StringOrInt;

int main()
{
    vector<StringOrInt> bools; 
    bools += 0, 0, 0, 0, 1, 0, 1, 1, 1, 1;

    boost::copy(
                bools | reversed,
                std::ostream_iterator<StringOrInt>(std::cout, ", "));

    return 0;
}

where the last few lines in the main only prints out the elements in the vector bools without actually providing an index to access the elements.

Thanks in advance!

Sid
  • 266
  • 5
  • 13
  • I suggest you write a small program to learn how to store and access data in a single variant, then check how to store things into a vector (`bools += 0, 0...` is broken; you could initialise the vector with the values you want instead of adding them after construction), then try your `for` loop (which needs semicolons not commas, and `i > 0` so that `myvec[i-1]` is safe). None of that is rocket science, and you can tackle it one thing at a time and use feedback from the compiler and perhaps `std::cout << x << '\n';` trace you add and/or an interactive debugger. – Tony Delroy Mar 28 '16 at 02:04
  • 1
    @TonyD welcome to [Boost Assign](http://www.boost.org/doc/libs/1_60_0/libs/assign/doc/index.html); gift from over a decade ago – sehe Mar 28 '16 at 02:09
  • 1
    And please don't call a vector that contains strings and int `bools`... :( – sehe Mar 28 '16 at 02:11
  • @sehe: thanks for pointing it out. – Tony Delroy Mar 28 '16 at 02:51

1 Answers1

1

There are many things really wrong with the for loop. I fixed those below.

You should create a variant to get some integer value from a variant:

struct as_int_visitor : boost::static_visitor<int> {
    int operator()(std::string const& s) const { return std::stoi(s); }
    int operator()(int i)                const { return i; }
};

Use it as follows:

int as_int(StringOrInt const& v) {
    return apply_visitor(as_int_visitor{}, v);
}

DEMO

Live On Coliru

#include <iostream>                         
#include <boost/assign/std/vector.hpp>
#include <boost/assign.hpp>
#include <boost/variant.hpp>                

#include <algorithm>

using namespace std;
using namespace boost::assign;

typedef boost::variant<std::string,int> StringOrInt;

struct as_int_visitor : boost::static_visitor<int> {
    int operator()(std::string const& s) const { return std::stoi(s); }
    int operator()(int i)                const { return i; }
};

int as_int(StringOrInt const& v) {
    return apply_visitor(as_int_visitor{}, v);
}

int main()
{
    vector<StringOrInt> values; 
    values += 0, 3, 4, 6, "42", 0, 1, 1, 1, 1;

    for (int i = values.size()-1; i > 0; --i) {
        std::cout << "At #" << i << " lives " << values[i] << " (evaluates to " << as_int(values[i]) << ")";

        if (as_int(values[i]) == 0 && as_int(values[i-1]) == 1){
            std::cout << " HIT\n";
        } else 
            std::cout << "\n";
    }
}

Prints:

At #9 lives 1 (evaluates to 1)
At #8 lives 1 (evaluates to 1)
At #7 lives 1 (evaluates to 1)
At #6 lives 1 (evaluates to 1)
At #5 lives 0 (evaluates to 0)
At #4 lives 42 (evaluates to 42)
At #3 lives 6 (evaluates to 6)
At #2 lives 4 (evaluates to 4)
At #1 lives 3 (evaluates to 3)
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Fantastic! Vector name is no longer `bools`! ;) The `as_int` variable was exactly what I needed, but am still a bit unsure of how it works. Could you explain? Thanks for you help! – Sid Mar 28 '16 at 23:58
  • It uses the Visitor pattern described here in the Boost documentation: [Basic Usage](http://www.boost.org/doc/libs/1_60_0/doc/html/variant/tutorial.html#variant.tutorial.basic) – sehe Mar 29 '16 at 00:00
  • The code throws a compilation error if the string element is of the sort, "hi", for example. If the iterator "sees" such a string, I would like for it to ignore it and move on to compare elements with non strings. – Sid Mar 29 '16 at 00:32
  • please post a self-contained sample of that, perhaps as a new question. Right now I can only guess. (Did you mean a runtime error in stoi?) – sehe Mar 29 '16 at 00:32
  • Yes. If you change the element "42" for "hi" in the above example and run it, the error is *"libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stoi: no conversion"*. – Sid Mar 29 '16 at 00:38
  • So, it's not compilation error at all. One way would be to use a "magic" number for illegal strings: http://coliru.stacked-crooked.com/a/c406041d7d598e9f – sehe Mar 29 '16 at 00:41