Страницы

Поиск по вопросам

среда, 4 декабря 2019 г.

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

#cpp #cpp14 #метапрограммирование


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

struct S {
    T1 t1;
    T2 t2;
    // и т.д.
} s;

template  f(const T& t, const char* name) { /* что-то */ }


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

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


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

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

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


Ответы

Ответ 1



Как предложил в комментариях к вопросу @KoVadim, можно использовать так называемые X Macro. С их использованием Ваша задача решается примерно следующим образом: #include #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 void 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

Ответ 2



Можно допилить мое решение. Оно предназначено для разбора параметров командной строки и помещения их в кортеж, к элементам которого можно обращаться по имени. При этом, имена на этапе компиляции заменяются на индексы элементов в кортеже. Как с этим работать: Нужно унаследовать класс от opt-parser #ifndef CONVOPTIONS_H #define CONVOPTIONS_H #include "opt-parser/optparser.h" struct optlist { static constexpr auto options=tuple_cat( OPTPARSER::makeO("input"), OPTPARSER::makeO("output") ); }; class ConvOptions:public OPTPARSER::Options { public: ConvOptions(int argc,char** argv); }; #endif // CONVOPTIONS_H После чего, можно обращаться к его полям по именам: ConvOptions opts(argc,argv); $(opts,"input")

Ответ 3



Это шкурка ответа с шагами его получения. Надо ещё везде распихать ссылки и добавить поддержку имён полей. http://ideone.com/6LOtIl http://ideone.com/ac32bj http://ideone.com/bG8q69 http://ideone.com/umN51y http://ideone.com/bxgu9H http://ideone.com/rddXvG #include #include using namespace std; template struct enumerate { static auto get(typed x) -> decltype(x.template get()) { return x.template get(); }; const static bool has_next = !is_same()), void>::value; typedef enumerate next; template