Печать значений всех полей в структуре С++

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

struct abc  
{  
    int a;  
    char b;  
}  

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

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

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

Ответ 1

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

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

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

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

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

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

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

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

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 методы в той или иной точке :)

Ответ 2

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

Существуют библиотеки (например, CAMP), которые реализуют функции отражения, поэтому, если вам действительно нужно отражение, вы должны использовать его.

Ответ 3

Существует не один, не в С++. Жесткая удача.

Ответ 4

Компиляторы С++ не создают метаданные. Таким образом, нет никакого способа сделать такую ​​вещь.

Ответ 5

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

Ответ 6

Это невозможно, потому что в С++ нет отражения. Однако, если вы не хотите сами писать код шаблона, вы всегда можете написать какой-нибудь инструмент, чтобы сделать это для вас.

Ответ 7

Это можно сделать с использованием шаблона дизайна посетителя:

struct MyStruct;  // Forward declaration

struct Writer
{
    virtual void operator(MyStruct& m) = 0;
};

struct MyStruct
{
    void    write(Writer& w)
    {
        // Invoke the writer method for this class.
        w(*this);
    }
    int a;
    double b;
};

struct File_Writer
{
    File_Writer(ofstream& output)
    : m_output(output)
    { ; }
    void operator(MyStruct& ms)
    {
        output << ms.a << endl;
        output << ms.b << endl;
    }
    ofstream&  m_output;
};

struct Display_Writer
{
    void operator(MyStruct& ms)
    {
        cout << "    a: " << ms.a << endl;
        cout << "    b: " << ms.b << endl;
    }
};

int main(void)
{
  MyStruct ms;
  ms.a = 5;
  ms.b = 4.2;

  // Write to the display, without changing methods in MyStruct
  Display_Writer  dw;
  ms.write(dw);

  // Write to a file without changing methods in MyStruct
  ofstream  my_file("me.txt");
  File_Writer    fw(my_file);
  ms.write(fw); // Notice that only the writer object changed.

  return 0;
}

Ответ 8

С С++ 17 (возможно, даже С++ 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 << ' ';
    }
);

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