Если бы был способ перебирать элементы данных простых структур, то решение вашей проблемы было бы простым. Модное слово для такой функциональности: (статическое) отражение . Однако язык C ++ не предоставляет возможности отражения (пока).
В некоторых особых случаях (и начиная с C ++ 14) существуют хаки, которые обеспечивают некоторый уровень отражения . Подтверждение концепции дано в Boost.PFR (ex magic_get) . Обратите внимание, что он не был (еще?) Утвержден в качестве официальной части Boost. Основные методы также объяснены в этом выступлении на конференции .
В качестве альтернативы, вы можете создавать свои собственные инструменты отражения, комментируя ваши структуры мета-информацией на их макете. Примеры в Boost можно найти в Boost.Fusion и Boost.Hana . Другие подходы используют внешние инструменты генерации кода (см., Например, siplasplas (прекращено?) Или Система мета-объектов Qt ).
Наконец, в вашем минимальном примере есть простой способ напечатать агрегаты, если вы можете превратить простые структуры в кортежи .
static_assert(__cplusplus >= 201703L, "example written for C++17 or later");
#include <iostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
using CMembers = std::tuple<int, char>;
struct C : CMembers {
using Members = CMembers;
using Members::Members;// inherit constructor
};
using BMembers = std::tuple<int, char, C>;
struct B : BMembers {
using Members = BMembers;
using Members::Members;// inherit constructor
};
using AMembers = std::tuple<int, int, B, char>;
struct A : AMembers {
using Members = AMembers;
using Members::Members;// inherit constructor
};
template<std::size_t... is, class... Ts, class F>
void foreach_tuple_element(
std::index_sequence<is...>,
const std::tuple<Ts...>& tuple,
F f
) {
( f( std::get<is>(tuple) ), ... );
}
template<class... Ts, class F>
void foreach_tuple_element(
const std::tuple<Ts...>& tuple,
F f
) {
foreach_tuple_element(std::index_sequence_for<Ts...>{}, tuple, f);
}
template<class T>
auto pretty_print(const T& x, std::string indent = "")
-> std::void_t<decltype(std::cout << indent << x << "\n")>
{
std::cout << indent << x << "\n";
}
template<class... Ts>
void pretty_print(const std::tuple<Ts...>& tuple, std::string indent = "") {
foreach_tuple_element(tuple, [indent] (auto&& x) {
pretty_print(x, indent + "\t");
});
}
template<class T, class MemberTuple = typename T::Members>
void pretty_print(const T& x, std::string indent = "") {
pretty_print(static_cast<const MemberTuple&>(x), indent);
}
int main() {
A a{1, 2, {3, 'p', {4, 'k'}}, 'w'};
pretty_print(a);
}