Info
-
Did you know about C++2X proposal for the Circle Meta-model for compilation-time meta-programming?
Example
#include <cstdio>
auto main() -> int {
std::puts("Hello world"); // during run-time
@meta std::puts("Hello circle"); // during compilation-time
}
Hello circle
ASM generation compiler returned: 0
Hello circle
Execution build compiler returned: 0
Program returned: 0
Hello world
Puzzle
- Can you implement
to_tuple_with_names
which returnsnamed
fields based on Circle Meta-model?
template<class T>
struct named {
T value{};
std::string_view name{};
};
template<class T> auto to_tuple_with_names(const T& t); // TODO
int main() {
{
struct empty { };
const auto & t = to_tuple_with_names(empty{});
expect(0 == std::tuple_size_v<std::remove_reference_t<decltype(t)>>);
}
{
struct trade {
std::int32_t price{42};
};
const auto & t = to_tuple_with_names(trade{});
expect(1 == std::tuple_size_v<std::remove_reference_t<decltype(t)>>);
expect(42 == std::get<0>(t).value and "price" == std::get<0>(t).name);
}
{
struct trade {
std::int32_t price{42};
std::uint32_t quantity{1'000u};
};
const auto & t = to_tuple_with_names(trade{});
expect(2 == std::tuple_size_v<std::remove_reference_t<decltype(t)>>);
expect(42 == std::get<0>(t).value and "price" == std::get<0>(t).name);
expect(1'000u == std::get<1>(t).value and "quantity" == std::get<1>(t).name);
};
}
Solutions
template<class T> auto to_tuple_with_names(const T& t) {
std::tuple<named<@member_types(T)>...> result;
result...[:] = { t...[:], @member_names(T) } ...;
return result;
}
template<class T> [[nodiscard]] auto to_tuple_with_names(const T& t) {
constexpr auto to_tuple_with_names = []<class... TNames, class... TValues>(const TValues&... values) {
return [&](const auto&... names) {
return std::make_tuple(named<TValues>{values, names}...);
};
};
return to_tuple_with_names(t.@member_values()...)(@member_names(T)...);
}
template<class T> auto to_tuple_with_names(const T& t) {
std::tuple<named<@member_types(T)>...> result;
@meta for(int i = 0; i < @member_count(T); ++i) {
std::get<i>(result) = { @member_value(t, i), @member_name(T, i) };
}
return result;
}
template<class T> auto to_tuple_with_names(const T& t) {
return std::make_tuple(named<@member_types(T)>{@member_values(t), @member_names(T)}...);
}
template <class T>
[[nodiscard]] constexpr auto to_tuple_with_names(const T &t) {
return std::make_tuple(
named<@member_types(T)>{t.@member_values(), @member_names(T)}...);
}
template<typename T, int I> auto get_member( T const & obj)
{
return named{ obj.@member_value(I), @member_name(T, I) };
}
template<class T> auto to_tuple_with_names(const T& t){
const int N = @member_count(T);
return [&]<int ... Is >( std::integer_sequence<int, Is ... > const & )
{
return std::make_tuple(get_member<T,Is>(t)...);
}(std::make_integer_sequence<int,N>{} );
};