Можно ли изменять тип переменной к которой мы обращаемся у структуры в цикле?

struct stringTable {
string surname;
string name;
string patronymic;
    int hash;
};
void seperation(string text, stringTable &personality){
    for (int i = 0; i < text.size(); i++) {
        bool skipSurname = false;
        bool skipName = false;
        if (text[i] != ' ' && !skipSurname) {
            personality.surname += text[i];
        }
        if (text[i] == ' ') {
            skipSurname = true;
            continue;
        }
        if (text[i] != ' ' && skipSurname && !skipName) {
            personality.name += text[i];
        }
        if (text[i] == ' ') {
            skipName = true;
            continue;
        }
        if (text[i] != ' ' && skipSurname && skipName) {
            personality.patronymic += text[i];
        }
    }
};

В задании существует некоторая база данных, состоящая из таблицы, в строках которой находится ФИО, между словами стоит 1 пробел. Я считываю строку в string, а затем хочу заполнить собственную структуру на раздельные слова. Для этого я написал функцию seperation, которая кажется мне длинной из-за различных булевых переменных. Я задумался вопросом: "А возможно ли менять динамически тип переменной, к которой я хочу обращаться?" Т.е. я хотел, чтобы у меня существовал массив имен переменных в структуре, которым я мог пользоваться, чтобы менять их и обращаться к различным переменным. Если моя идея покажется непонятной, то я просто хотел бы увидеть более оптимизированный вариант заполнения моей структуры строкой.


Ответы (2 шт):

Автор решения: gbg

В C++ нету (до C++20, там ожидается) интроспекции, то есть, язык не способен "понимать", из каких полей состоит структура, или как-то по этим полям ходить циклом.

Имеются разные обходные пути для этого, которые используют макросы (boost) или специально написанный препроцессор (moc в Qt).

Еще один способ - избавиться от полей, написав что-то такое:

#define GET_PART(name, index) std::string& name() { return fio[index]; }
class FIO
{
    std::vector<std::string> fio;
public:
    FIO(const std::string& textToParse)
    {
        //возможно, это не самый оптимальный, 
        //зато короткий способ порезать по пробелам
        std::istringstream iss(textToParse);           
        fio.insert(std::istream_iterator<std::string>{iss},
                   std::istream_iterator<std::string>()); 
        fio.resize(3); //гарантировать, чтобы все три части ФИО были на месте
                       //и выкинуть лишнее

    }
    GET_PART(LastName  , 0)
    GET_PART(FirstName , 1)
    GET_PART(MiddleName, 2)
};
#undef GET_PART
→ Ссылка
Автор решения: Harry

Массив имен сделать несложно - используя в качестве имен указатели, например -

string* arr[3] = {
    &personality.surname,
    &personality.name,
    &personality.patronymic
};

Так что

void seperation(const string& text, stringTable &personality)
{
    string* arr[3] = {
        &personality.surname,
        &personality.name,
        &personality.patronymic
    };

    istringstream is(text);
    for(int i = 0; i < 3; ++i) is >> *arr[i];
};

Или еще проще...

void seperation(const string& text, stringTable &personality)
{
    istringstream is(text);
    is >> personality.surname >> personality.name >> personality.patronymic;
};

Кстати, адекватно отработает отсутствие третьего (или даже второго с третьим) полей.

Только вот не понимаю, где у вас разные типы:

"А возможно ли менять динамически тип переменной, к которой я хочу обращаться?"

→ Ссылка