2

I'm relatively new to programming, and am currently learning C++. I'm doubtful if my logic in this is even correct, but here's something I've been trying to work out:

I have a simple program that outputs the size and content of a vector;

vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{ 10 };
vector<int> v5{ 10, 42 };
vector<string> v6{ 10 };
vector<string> v7{ 10, "hi" };
//and so on...........

bool firstPass= true;
for (auto i : v3){
    if (firstPass) cout << "Vector size:  " << v3.size() << ".\nElements: " << i << ", ";
    cout << i << ", ";
    firstPass= false;
}

If i want to iterate through another vector, i have to manually change the v3 to vX, but what i'd like is for this snippet of code to go through all the vectors.

I've tried several methods, such as creating a vector<string> V8{"v1","v2","v3"..}
for (auto i : V8[counter])

but essentially I've failed because "v1" != v1.(This is where i got the "convert string to vector" idea from, but something tells me this isn't the way to go about doing this...)

Any help & criticism would be greatly appreciated, and i apologize as this will probably get filed under too specific or even useless, considering my way of trying to solve this is probably faulty and i asked the wrong question!

7
  • If you wan to iterate the vectors, the easiest thing is to put them all in a container that's iterable - e.g. another vector. So, you then have vector<vector<int>> = { { }, {10}, {10,42}, {10}, {10,42} };. You can then iterate using nested for loops. But you can't mix in strings so easily - you could have a separate vector<vector<string>>, or you could create an abstraction layer using variants (boost::any, boost::variant, an OO runtime-polymorphic hierarchy for the vectors)... it's probably beyond what you're ready to have to write. Commented Aug 6, 2014 at 3:22
  • Or, if your vectors already exist, you can make a vector (or just an initializer list) of pointers to the existing vectors. (But you'll still need separate collections of different types of vectors.) Commented Aug 6, 2014 at 3:26
  • @TonyD, the vector of vectors sounds great, but i am specifically plagued by the same issue as before; how would i add a huge amount of existing vectors to a vector<vector<int>>, without having to vectorOfVectors.push_back(vectorName) for each vector? The following code would write v1,v2,v3 in place of vectorName each time, but those would be strings and hence of the wrong type: vectorOfVectors.push_back("v"+to.string(counter)) counter++; Commented Aug 6, 2014 at 3:55
  • @Boop that isn't how the language works. You have to address the item(s) of your goal somehow, and in C++ that eventually starts with an id at compile-time; not run-time. that id could be a vector of vectors, an array, what have you, but it has to be compile-time known somehow. Were it your own class you could maintain a live static-list of objects and just dump the list, but the standard lib provides no such facility. Maybe a template-wrapper, but I don't see how it would be worth the trouble. variadic preprocessing may have merit, but again, you have to want it bad. Commented Aug 6, 2014 at 4:02
  • @Boop: just how many of these vectors do you have? Commented Aug 6, 2014 at 4:31

5 Answers 5

1

To solve your literal problem of looking up a variable by a string representing the variable's name: The only facility that POSIX supplies to look up a global variable by name is dlsym(). It only works for globals, and you have to declare your functions with extern "C" to suppress C++ name mangling (global variable names don't get mangled).

#include <vector>
#include <assert.h>
#include <dlfcn.h>

std::vector<int> v1;

int main () {
    void *h = dlopen(0, RTLD_NOW);
    void *v = dlsym(h, "v1");
    assert(v == &v1);
}

To get the sample above to work, you need to compile with g++ -rdynamic prog.cpp -ldl.

The limitation of this technique is that you need to know the type of the pointer that is returned a priori, and cast it accordingly.

If you are willing to "pass" your arrays to a function to print out each array for you, you can implement a variadic template function to do this.

template <typename Vector>
void print_all_vectors (Vector v) {
    /* enforce we are only interested in vectors */
    const std::vector<typename Vector::value_type> &vr = v;
    std::cout << "Vector size:  " << vr.size() << ".";
    if (!vr.empty()) std::cout << "\nElements";
    bool first = true;
    for (auto i : vr) {
        std::cout << (first ? ": " : ", ") << i;
        first = false;
    }
    std::cout << '\n';
}

template <typename Vector, typename... Vectors>
void print_all_vectors (Vector v, Vectors... vectors) {
    print_all_vectors(v);
    print_all_vectors(vectors...);
}

The first template in the code above prints out a vector. The second template function recursively unpacks the variadic parameter list and passes each to the first template function.

Using the functions is easy, illustrated below:

std::vector<int> v1{1, 3, 5, 7};
std::vector<std::string> v2{"doh", "ray", "me"};
print_all_vectors(v1, v2);
Sign up to request clarification or add additional context in comments.

Comments

1

You'll need C++11, but it's definitely possible:

template<typename V>
void PrintVector(V const& v) {
  for (auto elem : v) std::cout << elem << " ";
  std::cout << std::endl;
}
template <typename V, typename ... Vectors>
void PrintAll(V const& v1, Vectors... vtail)
{
   PrintVector(v);
   PrintAll(vtail...);
}
PrintAll(v1, v2, v3, v4, v5, v6, v7, v8, v9);

4 Comments

+1 not sure if this was what was wanted (the question's '"V1" != v1" complaint made me think some way of treating identifiers more like text - with concatenation - was desired), but rereading the question the vector V8{"v1","v2","v3"..} suggests the OP's open to such an approach and this does it very elegantly....
@TonyD: The OP already admits that his "string" idea was probably the wrong approach to start with. In the end, you need some way to tell the compiler which objects need to be grouped together. Obviously you can't just "print every vector in the program". What if std::cout used one internally ?!
all your individual points are correct, but they make it sound like a programmer-typed list or some kind of naive (and in current C++ non-existent) introspection are the only alternatives. Anyway, I'm sure we both know what's on offer and what the alternatives are - arrays / vectors / template <int N> ... / preprocessor iteration / dlsym using some naming convention / code-generating scripts etc. etc. etc..
@TonyD: Sour grapes as this is basically my answer posted an hour earlier.
0

You need something to iterate on if you need something that is resolved in runtime, you could use a vector of vectors but they should be of the same type (vector of strings mixed with int is not be possible since they are different types due to the template instantation ) On the other hand you can use the preprocessor and macro expansion for static stuff or templates

Comments

0

(This is more a comment than an answer, but am listing a bit of code too long for a comment...)

If you don't want to clean up the code to only have a vector<vector<int>> + vector<vector<string>>, vector<vector<boost::variant<int,string>>>, or similar, then you could create e.g. vector<vector<int>*> and vv.push_back(&v1); vv.push_back(&v2); et al to avoid the expense of copying.

There's no way to easy iterate over variables called v1, v2, v3 etc. (the preprocessor can do it but it's complicated - see the boost preprocessor library if you want to pursue that).

It might be easiest to settle for a more concise convenience function to do the push_backs... something like:

vector<vector<int>>& operator<<(vector<vector<int>>& vv, vector<int>& v)
{
    vv.push_back(v);
    return vv;
}

Then you can code...

vv << v1 << v2 << v3 << v4 << v5;

Ideally, you'd put the operator in an anonymous namespace so only your code sees it, avoiding accidental usage or potential conflicts in other code.

4 Comments

The easiest way to iterate over {v1, v2, v3, v4, v5, v6, v7, v8} is via variadic templates. Boost preprocessor is a pre-C++11 hack.
@MSalters: it's generating such code that's the issue - with the preprocessor you could create some #define X such that X(v, 1, 1000) substituted v1, v2, v3, v4..., v999, v1000 - then pass output to a variadic template, embed it in an initialiser_list or whatever you needed. It's definitely hackish, but there are still areas of utility untouched by C++11.
TBH I'd use Template Metaprogramming to define v<1>, v<2>, ... in those cases. If v1 and v2 are that related they shouldn't be using two distinct identifiers.
@MSalters: and round it goes... the OP commented "It was the idea behind it that was bugging me, just seemed like something that must have a solution out there", so what's sensible/best was kind of missing from the get go.
0

If you're simply convering a string into a vector<int> then this example may give you an idea how to do it in general.

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string str = "1234567890";
    vector<int> intedStr;

    for (size_t i = 0; i < str.length(); i++)
    {
        intedStr.push_back((int)str[i] - '0');
    }
    for (size_t i = 0; i < intedStr.size(); i++)
    {
        cout << intedStr[i] << " ";
    }

    system("pause");
}

Note: this is not a safe function. What happens if you want to covert "abcsd" to vector<int>?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.