Перечисление полей структуры

480
07 февраля 2017, 20:48

Есть структура и функции:

struct S {
    T1 t1;
    T2 t2;
    // и т.д.
} s;
template <class T> f(const T& t, const char* name) { /* что-то */ }

Необходимо, чтобы работал следующий (псевдо)код:

for (поле : поля(s))
    f(поле.значение, поле.имя);

То есть, надо как-то перечислить все поля структуры, получая их тип, значение и имя в виде строки.

Я знаю, что рефлексии в языке C++ нет. Но здесь не нужна рефлексия при выполнении, нужна рефлексия на стадии компиляции или линковки. При этом можно как угодно извращаться с объявлением структуры S, но нельзя трогать функцию f. Но в итоге всё равно должна быть каким-либо образом создана либо структура либо что-то структурообразное, поволяющее обращаться к полям (s.t1 и т.д.).

Сторонние библиотеки использовать нельзя, но можно использовать макросы, шаблоны и вообще все доступные возможности C++14.

Answer 1

Как предложил в комментариях к вопросу @KoVadim, можно использовать так называемые X Macro. С их использованием Ваша задача решается примерно следующим образом:

#include <iostream>
#define STRUCT_FIELDS \
    X(int, i) \
    X(float, f) \
    X(const char*, c)
struct S {
    #define X(type, name) type name;
        STRUCT_FIELDS
    #undef X
};
template<typename T> f(const T& t, const char* name)
{
    std::cout << name << " = " << t << std::endl;
}
void printStruct(const S& s) {
    #define X(type, name) f(s.name, #name);
        STRUCT_FIELDS
    #undef X
}
int main(int argc, char* argv[]) {
    S s;
    s.i = 1;
    s.f = 10.1;
    s.c = "s";
    printStruct(s);
}

Результат работы программы:

i = 1
f = 10.1
c = s
Answer 2

Можно допилить мое решение. Оно предназначено для разбора параметров командной строки и помещения их в кортеж, к элементам которого можно обращаться по имени. При этом, имена на этапе компиляции заменяются на индексы элементов в кортеже.

Как с этим работать:

Нужно унаследовать класс от opt-parser

#ifndef CONVOPTIONS_H
#define CONVOPTIONS_H
#include "opt-parser/optparser.h"
struct optlist
{
    static constexpr auto options=tuple_cat(
                OPTPARSER::makeO<std::string>("input"),
                OPTPARSER::makeO<std::string>("output")
                );
};
class ConvOptions:public OPTPARSER::Options<optlist>
{
public:
    ConvOptions(int argc,char** argv);
};
#endif // CONVOPTIONS_H

После чего, можно обращаться к его полям по именам:

ConvOptions opts(argc,argv);
$(opts,"input")
READ ALSO
Разный статус заказа в один момент времени для разных пользователей

Разный статус заказа в один момент времени для разных пользователей

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

467
Среднее значение из таблицы sql

Среднее значение из таблицы sql

Есть задача сформировать базу для личных целейИсходные данные более 2000 заданий 5 работников 2 вида оценок:

571
MySQL изменение даты в формате `text`

MySQL изменение даты в формате `text`

Есть поле формата text содержащее дату, пример даты: 0205

518
Ошибка при вставке Blob поля в таблицу MySQL

Ошибка при вставке Blob поля в таблицу MySQL

Имеется код вставки в БД:

455