Created
February 16, 2024 23:09
-
-
Save lemire/c9ec2891d11287f4e883fdf284ff5ff8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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