Reflection for aggregates
// Copyright 2020 Andrzej Krzemienski.
//
// This shows how to implement a basic reflection for aggregate
// types in C++17.
// This code has been inspired by Precise and Flat Reflection
// library by Antony Polukhin at:
// https://github.com/apolukhin/magic_get
#include <cassert>
#include <iostream>
#include <string>
#include <type_traits>
#include <tuple>
struct Record
{
std::string name;
int age;
double salary;
};
struct Point
{
int x;
int y;
};
struct init
{
template <typename T>
operator T(); // never defined
};
template <unsigned I>
struct tag : tag<I - 1> {};
template <>
struct tag<0> {};
template <typename T>
constexpr auto size_(tag<4>)
-> decltype(T{init{}, init{}, init{}, init{}}, 0u)
{ return 4u; }
template <typename T>
constexpr auto size_(tag<3>)
-> decltype(T{init{}, init{}, init{}}, 0u)
{ return 3u; }
template <typename T>
constexpr auto size_(tag<2>)
-> decltype(T{init{}, init{}}, 0u)
{ return 2u; }
template <typename T>
constexpr auto size_(tag<1>)
-> decltype(T{init{}}, 0u)
{ return 1u; }
template <typename T>
constexpr auto size_(tag<0>)
-> decltype(T{}, 0u)
{ return 0u; }
template <typename T>
constexpr size_t size()
{
static_assert(std::is_aggregate_v<T>);
return size_<T>(tag<4>{}); // highest supported number
}
template <typename T, typename F>
void for_each_member(T const& v, F f)
{
static_assert(std::is_aggregate_v<T>);
if constexpr (size<T>() == 4u)
{
const auto& [m0, m1, m2, m3] = v;
f(m0); f(m1); f(m2); f(m3);
}
else if constexpr (size<T>() == 3u)
{
const auto& [m0, m1, m2] = v;
f(m0); f(m1); f(m2);
}
else if constexpr (size<T>() == 2u)
{
const auto& [m0, m1] = v;
f(m0); f(m1);
}
else if constexpr (size<T>() == 1u)
{
const auto& [m0] = v;
f(m0);
}
}
template <typename T>
auto as_tuple(T const& v)
{
static_assert(std::is_aggregate_v<T>);
if constexpr (size<T>() == 4u)
{
const auto& [m0, m1, m2, m3] = v;
return std::tie(m0, m1, m2, m3);
}
else if constexpr (size<T>() == 3u)
{
const auto& [m0, m1, m2] = v;
return std::tie(m0, m1, m2);
}
else if constexpr (size<T>() == 2u)
{
const auto& [m0, m1] = v;
return std::tie(m0, m1);
}
else if constexpr (size<T>() == 1u)
{
const auto& [m0] = v;
return std::tie(m0);
}
}
int main()
{
Point pt{2, 3};
Record rec {"Baggins", 111, 999.99};
auto print = [](auto const& member) {
std::cout << member << " ";
};
for_each_member(rec, print);
for_each_member(pt, print);
assert(as_tuple(Point{1, 1}) < as_tuple(pt));
}
Like this:
Like Loading...