Печать значений всех полей в структуре C ++ - PullRequest
20 голосов
/ 03 мая 2010

Рассмотрим простую структуру:

struct abc  
{  
    int a;  
    char b;  
}  

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

*a = [some value]  
b = [some character]*

Каков наилучший способ добиться этого для произвольной структуры без необходимости писать функцию dump ... (...) для каждой структуры, с которой я сталкиваюсь?

Ответы [ 5 ]

28 голосов
/ 03 мая 2010

Кажется, вы уже нашли решение, но я немного расширю.

То, к чему вы обращаетесь, называется Reflection, то есть способность объекта описывать себя.

Большинство языков могут реализовывать отражение благодаря метаданным. Например, в Python функции и атрибуты объекта хранятся в элементе словаря.

C ++ не имеет никакой собственной системы отражения в отличие от C # или Java, которая предотвращает (например) этот тип автоматической печати / сериализации или десериализации.

Тем не менее, C ++ имеет очень мощную поддержку метапрограммирования, которая позволяет нам (посредством использования шаблонов) эмулировать отражение (во время компиляции). Обычно это делается с помощью Boost.Fusion , библиотеки, предназначенной для перехода от времени компиляции к времени выполнения.

Как показывает пример, приведенный в вашей ссылке, макрос BOOST_FUSION_ADAPT_STRUCT позволяет вам взять стандартный struct и присвоить ему необходимый интерфейс, который будет обрабатываться как последовательность Fusion.Sequence.

Другим примером может быть использование Fusion.Vector или Fusion.Map для хранения атрибутов класса и последующего предоставления этой последовательности автоматическим методам печати / сериализации / десериализации.

Однако у этой системы есть ограничение: метапрограммирование плохо сочетается с OO-программированием.

struct Base { char a; };            // Adapt
struct Derived: Base { char b; };   // Adapt

void print(Base const& b) { boost::fusion::for_each<Base>(b, Print()); }

будет печатать только элемент Base (здесь a). При использовании полиморфизма необходимо использовать методы virtual в той или иной точке:)

3 голосов
/ 03 мая 2010

Вам нужно "отражение", чтобы сделать это. Отражение не предоставляется изначально в C ++ или только для минимальной информации (введите идентификаторы / имена).

Существуют библиотеки (например, CAMP ), которые реализуют функции отражения, поэтому, если вам ДЕЙСТВИТЕЛЬНО нужно отражение, вам следует использовать одну из них.

2 голосов
/ 03 мая 2010

Там нет ни одного, не в C ++. Не повезло.

0 голосов
/ 10 апреля 2018

С C ++ 17 (возможно, даже C ++ 14) и некоторыми сумасшедшими русскими взломами - это можно сделать частично. То есть вы можете печатать значения типов по порядку, но не можете получить имена полей.

Соответствующей библиотекой является Антоний Полухин "magic_get" . В частности, он предлагает механизм итерации "для каждого поля" , который принимает шаблонную лямбду с параметром auto Пример:

struct simple {
    int a;
    char b;
    short d;
};

simple x {42, 'a', 3};
std::stringstream ss;

boost::pfr::for_each_field(
    x,
    [&ss](auto&& val) {
        ss << val << ' ';
    }
);

Ответ перенесен из смежного / дублирующего вопроса - так как здесь никто не упомянул это.

0 голосов
/ 03 мая 2010

Если вы используете C ++ в .NET, вы можете потенциально использовать System.Reflection , чтобы посмотреть на внутренности вашей структуры. Однако неуправляемый C ++ редко, если вообще когда-либо, хранит метаданные об объектах такого типа.

...