How to achieve iteratively several variables whose names differ only in number in C ++?

I need a method to help me to achieve variables called "comboBox1", "comboBox2", etc. each one in a cycle. I would like to change the code, for example:

//proceed comboBox1 //proceed comboBox2 //proceed comboBox3 //proceed comboBox4 //proceed comboBox5 //proceed comboBox6 

IN:

 for (int i = 1; i < numberOfBoxes; i++) { //proceed comboBox(i) } 

I tried to find something like eval, but google did not give anything suitable. I also tried pre-processing the name using the ## operator, but there seems to be no way to put the current integer value in a macro.

+4
source share
9 answers

The simplest solution is to put them all in an array and an iterator for this:

 // I've made up a type, but you get the idea. std::vector<ComboBox *> combos; combos.insert(comboBox1); combos.insert(comboBox2); combos.insert(comboBox3); combos.insert(comboBox4); combos.insert(comboBox5); combos.insert(comboBox6); 

Now you can iterate over combos. The main problem is that C ++ is not reflected. Thus, you cannot create a string at runtime and get the address of an object or function as you can in some other languages.

EDIT: I just saw that you are using Qt. In this case you should use:

 QList<T> qFindChildren ( const QObject * obj, const QString & name ); 

or

 QList<T> qFindChildren ( const QObject * obj, const QRegExp & regExp); 

This allows you to get a list based on names generated at runtime . For instance:

 QList<QComboBox *> combos = qFindChildren(ui, QRegExp("combo[0-9]+")); 

then you can just iterate over it!

+15
source

The only way I know how to do this is to create them in code / dynamically and in an array. (Not through the wizard). You are not alone in discovering this flaw in the MFC master (I suppose).

Alternatively, if your resources are consistent in the resource file (again, I accept an MFC-like implementation), you can iterate over the resource identifiers to get the resources. This assumes that they have consecutive resource identifiers. I have been using this method recently. It's good. Not sure if this is what you are looking for or will work with your GUI.

+4
source

In C ++, there is no way to identify a variable by name at run time. Instead of using a bunch of discrete variables with names like comboBox1, comboBox2, etc., why not create a ComboBoxes array that you can iterate over? Then your loop will look like this:

 for (int i = 1; i < numberOfBoxes; i++) { doSomething(comboBoxes[i]); } 
+3
source

If you are in preprocessor hacks, see the Boost.Preprocessor library:

 // Shamelessly copied from the Boost docs, and only slightly // adapted. (and probably breaking it ;) #include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #define DO_SOMETHING(z, n, text) BOOST_PP_CAT(text, n)->DoSomething(); BOOST_PP_REPEAT_FROM_TO(0, 3, DO_SOMETHING, comboBox) 

will expand to the following:

 comboBox0->DoSomething(); comboBox1->DoSomething(); comboBox2->DoSomething(); 
+3
source

I used the following approach to register functions, but you can try applying it in your case, I hope it guarantees this C-style workaround that does not take into account spaces:

 #define GET_COMBO_BOX(x,y) x ## y for (int i = 1; i < numberOfBoxes; i++) GET_COMBO_BOX(comboBox1,i); 

This clearly will NOT do what you want, since I am determined at compile time, and the macro is spent on preprocessing, but it will give you an idea of ​​how to pre-generate function calls.

Here is a more complete example of where macro concatenation is used:

 #include<iostream> #include<string> using namespace std; template< class E > struct EnumNames { static const char* const* names; static int names_size; }; #define REGISTER_ENUM( e ) \ const char* const* EnumNames< e >::names = e ## _names; \ int EnumNames< e >::names_size = sizeof( e ## _names ) / sizeof( const char* ); enum ElementType { NEURON, SYNAPSE }; const char* const ElementType_names[] = { "N", "S" }; REGISTER_ENUM( ElementType ) enum TokenMainType { EP, IP, NT, AI }; const char* const TokenMainType_names[] = { "EP", "IP", "NT", "AI" }; REGISTER_ENUM( TokenMainType ) template<class E> ostream& operator <<(ostream& os, const E& e) { if (e > EnumNames< E >::names_size) cout << "Error" << endl; os << EnumNames< E >::names[e]; return os; } template<class E> istream& operator >>(istream& is, E& e) { std::string tmp_e_string; is >> tmp_e_string; for (int i = 0; i < EnumNames< E >::names_size; ++i) { if (tmp_e_string == EnumNames< E >::names[i]) { e = E(i); return is; } } cerr << "Fehler: tmp_nntype_string: " << tmp_e_string << endl; return is; } int main (int argc, char **argv) { ElementType test1(NEURON); cout<<string(EnumNames<ElementType>::names[test1])<<endl; } 
+2
source

You will need to store the variables in an array.

eg

 mComboBoxes[MAX_COMBOBOXES]; 

//initialization

 for (int i = 0; i < numberOfBoxes; i++) { mComboBoxes[i]; } 

Note that arrays have zero indexes.

+1
source

Use arrays. This is what they are for. Or containers.

 T combobox_array[ N ]; // N comboboxes for (int i = 0; i < N; ++i) process(combobox_array[ i ]); // note array indices are 0 to N-1 

Or, with STL

 vector<T> ca(N); for_each(ca.begin(), ca.end(), do_something); 
+1
source

What's happening?

You need another level of indirection. Perhaps keep pointers to your combo boxes in a vector, which you can repeat later.

+1
source

Is there a reason why you cannot have an comboBox array / vector / list?

 std::vector<ComboBox> comboBoxes; 

or is it even better to keep a list of pointers to comboBoxes?

 std::vector<ComboBox*> comboBoxPtrVec; ComboBox* comboBox1 = new ComboBox(); ComboBox* comboBox2 = new ComboBox(); comboBoxPtrVec.push_back( comboBox1 ); comboBoxPtrVec.push_back( comboBox2 ); for (insigned int i = 0; i < comboBoxPtrVec.size(); ++i) { // process comboBox comboBoxPtrVec[i]->DoSomething(); } 
+1
source

All Articles