Как достичь итеративно нескольких переменных, имена которых отличаются только числом в C ++? - PullRequest
4 голосов
/ 19 февраля 2009

Мне нужен метод, помогающий мне, чтобы получить доступ к переменным с именами, такими как «comboBox1», «comboBox2» и т. Д., Каждая из которых в цикле. Я хотел бы изменить код как:

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

В

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

Я пытался найти что-то вроде 'eval', но Google не дал ничего подходящего. Я также попытался предварительно обработать имя с помощью оператора ##, но, похоже, нет способа поместить текущее целочисленное значение в макрос.

Ответы [ 9 ]

15 голосов
/ 19 февраля 2009

Самое простое решение - поместить их все в массив и итератор для этого:

// 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);

Теперь вы можете перебирать комбинации. Основная проблема в том, что у С ++ нет отражения. Таким образом, вы не можете сгенерировать строку во время выполнения и получить адрес объекта или функции, как в некоторых других языках.

РЕДАКТИРОВАТЬ: Я только что видел, что вы используете Qt. В этом случае вы должны использовать:

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

или

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

Это позволяет вам получить список на основе сгенерированных во время выполнения имен . Например:

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

тогда вы можете просто повторить это!

4 голосов
/ 19 февраля 2009

Единственный способ, которым я знаю, как это сделать - это создать их в коде / динамически и в массиве. (Не через мастера) Вы не одиноки в поиске этого недостатка мастера MFC (я полагаю) мастера.

В качестве альтернативы, если ваши ресурсы расположены последовательно в файле ресурсов (опять же я предполагаю, что MFC-подобная реализация), вы можете перебирать идентификаторы ресурсов для получения ресурсов. Это предполагает, что у них есть последовательные идентификаторы ресурса. Я использовал этот метод в последнее время. Работало нормально. Не уверен, что это то, что вы ищете или будете работать с вашим графическим интерфейсом.

3 голосов
/ 19 февраля 2009

Если вы занимаетесь взломом препроцессора, обратитесь к библиотеке Boost.Preprocessor:

// 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)

будет расширяться до чего-то вроде:

comboBox0->DoSomething();
comboBox1->DoSomething();
comboBox2->DoSomething();
3 голосов
/ 19 февраля 2009

В C ++ нет способа идентифицировать переменную по имени во время выполнения. Вместо того, чтобы использовать набор дискретных переменных с именами, такими как comboBox1, comboBox2 и т. Д., Почему бы не создать массив ComboBox, который вы можете перебирать? Тогда ваш цикл будет выглядеть так:

for (int i = 1; i < numberOfBoxes; i++) {
   doSomething(comboBoxes[i]);
}
2 голосов
/ 19 февраля 2009

Я использовал следующий подход для регистрации функций, но вы можете попробовать применить его в вашем случае, надеюсь, это оправдывает обходной путь в стиле C, который не учитывает пробелы:

#define GET_COMBO_BOX(x,y) x ## y

for (int i = 1; i < numberOfBoxes; i++) 
  GET_COMBO_BOX(comboBox1,i);

Это, очевидно, НЕ будет делать то, что вы хотите, так как i определяется во время компиляции, а макрос расходуется на предварительную обработку, но это даст вам представление о том, как предварительно генерировать вызовы функций.

Вот более полный пример, где используется конкатенация макросов:

#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;

}
1 голос
/ 19 февраля 2009

Есть ли причина, по которой вы не можете иметь массив / вектор / список comboBox'ов?

std::vector<ComboBox> 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 голос
/ 19 февраля 2009

Что такое "продолжить"?

Вам нужен еще один уровень косвенности. Возможно, храните указатели на поля со списком в векторе, который вы можете повторить позже.

1 голос
/ 19 февраля 2009

Использовать массивы. Вот для чего они здесь. Или контейнеры.

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

Или с STL

vector<T> ca(N);
for_each(ca.begin(), ca.end(), do_something);
1 голос
/ 19 февраля 2009

Вам нужно будет хранить ваши переменные в массиве.

* 1003 например *

mComboBoxes[MAX_COMBOBOXES];

// инициализация

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

Обратите внимание, что массивы имеют нулевые индексы.

...