Skip to content

Instantly share code, notes, and snippets.

@lemire
Created February 16, 2024 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lemire/c9ec2891d11287f4e883fdf284ff5ff8 to your computer and use it in GitHub Desktop.
Save lemire/c9ec2891d11287f4e883fdf284ff5ff8 to your computer and use it in GitHub Desktop.
// See https://twitter.com/pdimov2/status/1462802234761170949
#include <array>
#include <string_view>
#include <string>
#include <iostream>
// For now experimental/reflect is not available generally, but
// it should be standardized for C++ 26 ???? Still, we have
// access to it with the very latest llvm.
#include <experimental/reflect>
// We want to have access to the names a, b, c.
// Because we want to produce a JSON document that goes...
// {"a":....., "b":..., "c":....} but for that, we need
// the names "a", "b", "c" as strings accessible in C++.
struct S {
int a;
int b;
double z;
};
namespace reflect = std::experimental::reflect;
// source: https://rebraws.github.io/CppDetectMemberVariables/
template <class... T>
class Helper { // Note: We could have used a struct too
public:
static constexpr std::array<std::string_view, sizeof...(T)> getNames() {
return {std::experimental::reflect::get_name_v<T>...};
}
};
void z() {
using mo = reflexpr(S);
using member_sequence = std::experimental::reflect::get_public_data_members_t<mo>;
}
template<typename T>
requires std::is_aggregate_v<T>
constexpr std::size_t size() {
if constexpr (std::is_array_v<T>) {
return std::extent_v<T>;
}
else {
using Reflected_t = reflexpr(T);
using data_members = reflect::get_data_members_t<Reflected_t>;
return reflect::get_size_v<data_members>;
}
}
template<typename T, typename Func>
requires std::is_aggregate_v<T>
void for_each_member(const T& t, Func func) {
constexpr auto T_size = size<T>();
if constexpr (std::is_array_v<T>) {
for (const auto& i : t) {
func(i);
}
}
else {
using Reflected_t = reflexpr(T);
using data_members = reflect::get_data_members_t<Reflected_t>;
[&] <size_t... ints>(std::index_sequence<ints...>) {
std::tuple args{ reflect::get_pointer_v<reflect::get_element_t<ints, data_members>>... };
auto application = [&](auto&&... args) { (func(t.*args), ...); };
std::apply(application, args);
}(std::make_index_sequence<T_size>{});
}
}
int y() {
std::string ts{ "123" };
struct X { const std::string s; } x{ ts };
struct Y { double a[2]{ 3., 2. }, b{}, c{}, d{}; } y;
Y ys[10];
struct Z { std::mutex m; } z;
std::cout << size<X>() << std::endl;
std::cout << size<Y>() << std::endl;
std::cout << size<decltype(ys)>() << std::endl;
std::cout << size<Z>() << std::endl;
auto print = [](const auto& member) {
if constexpr (!requires { std::cout << member; }) {
std::cout << "[" << &member << "] ";
}
else {
std::cout << member << ' ';
}
};
for_each_member(x, print);
std::cout << std::endl;
for_each_member(y, print);
std::cout << std::endl;
for_each_member(ys, print);
std::cout << std::endl;
for_each_member(z, print);
std::cout << std::endl;
return 0;
}
auto main() -> int {
using mo = reflexpr(S);
using member_sequence = std::experimental::reflect::get_data_members_t<mo>;
using unpacked = std::experimental::reflect::unpack_sequence_t<Helper, member_sequence>;
static constexpr auto names = unpacked::getNames();
std::string_view x = names[1];
printf("%*s\n", (int)x.size(), x.data());
return x == "b";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment