254.md
September 5, 2022 ยท View on GitHub
Example
template<class... Ts>
struct print_enum {
void operator()() {
((std::cout << meta::get_name_v<meta::get_type_t<Ts>> << ':' << meta::get_name_v<Ts> << std::endl), ...);
}
};
enum class Trading { Quant, Lab };
int main() {
std::cout << meta::get_name_v<reflexpr(Trading)> << std::endl // prints Trading
<< meta::get_name_v<reflexpr(Trading::Quant)> << std::endl // prints Quant
<< meta::get_name_v<reflexpr(Trading::Lab)> << std::endl; // prints Lab
meta::unpack_sequence_t<print_enum, meta::get_enumerators_t<reflexpr(Trading)>>{}(); // prints Trading::Quant, Trading::Lab
}
Puzzle
- Can you implement
to_stringfunction which returns string representation for given type:type_name{field_type:field_name,...}?
template<class T> auto to_string(); // TODO
struct empty {};
struct foo {
int i;
double d;
};
struct bar {
foo f;
};
int main() {
using namespace boost::ut;
using std::literals::string_literals::operator""s;
"reflexpr to_string"_test = [] {
expect("empty{}"s == to_string<reflexpr(empty)>());
expect("foo{int:i,double:d}"s == to_string<reflexpr(foo)>());
expect("bar{foo:f}"s == to_string<reflexpr(bar)>());
};
}
Solutions
template <class... Ts>
struct stringify_members {
auto operator()() const {
const auto type_and_name = [] <class T> {
return std::string{meta::get_name_v<meta::get_type_t<T>>} + ':' + meta::get_name_v<T>;
};
std::string s{("" + ... + (type_and_name.template operator()<Ts>() + ','))};
if constexpr (sizeof...(Ts) > 0) {
s.pop_back();
}
return s;
}
};
template <class T> auto to_string() {
return std::string{meta::get_name_v<T>} + '{'
+ meta::unpack_sequence_t<stringify_members, meta::get_data_members_t<T>>{}() + '}';
}
template<class... Ts>
struct type_name {
auto operator()(std::stringstream& str) {
auto comma = sizeof...(Ts) > 1;
((str << meta::get_name_v<meta::get_type_t<Ts>> << ':' << meta::get_name_v<Ts> << (comma ? "," : ""), comma = false), ...);
}
};
template<class T>
auto to_string() {
std::stringstream str{};
str << meta::get_display_name_v<T> << '{';
meta::unpack_sequence_t<type_name, meta::get_data_members_t<T>>{}(str);
str << '}';
return str.str();
}
template<class... Ts>
struct type_name {
auto operator()(std::stringstream& str) {
auto comma = sizeof...(Ts) > 1;
((str << meta::get_name_v<meta::get_type_t<Ts>> << ':' << meta::get_name_v<Ts> << (comma ? "," : ""), comma = false), ...);
}
};
template<class T>
auto to_string() {
std::stringstream str{};
str << meta::get_display_name_v<meta::get_aliased_t<reflexpr(T)>> << '{';
meta::unpack_sequence_t<type_name, meta::get_data_members_t<reflexpr(T)>>{}(str);
str << '}';
return str.str();
}
template<class... Ts>
struct memString
{
auto operator()() {
std::string str = ( std::string{meta::get_name_v<meta::get_type_t<Ts>>} + std::string{":"} + std::string{meta::get_name_v<Ts>} +"," + ... + std::string{});
if(str.size() > 0)
str = str.substr(0,str.size()-1);
return str;
}
};
template<class T> auto to_string() {
std::string res = std::experimental::reflect::get_name_v<T>;
res += "{";
res += meta::unpack_sequence_t<memString, meta::get_data_members_t<T>>{}();
res += "}";
return res;
}
template <typename... TMembers>
struct to_string_helper {
auto operator()() const {
const auto format_member = [] <typename TMember> {
return std::format("{}:{},",
meta::get_name_v<meta::get_type_t<TMember>>,
meta::get_name_v<TMember>);
};
if constexpr (sizeof...(TMembers) > 0) {
auto s = std::string{("" + ... + (format_member.template operator()<TMembers>()))};
s.pop_back();
return s;
} else {
return "";
}
}
};
template<typename T>
[[nodiscard]] auto to_string() {
return std::format("{}{{{}}}",
meta::get_name_v<T>,
meta::unpack_sequence_t<to_string_helper, meta::get_data_members_t<T>>{}());
}
template <auto Expr>
struct expr {
template <class... Ts>
struct fn {
auto operator()() { return Expr.template operator()<Ts...>(); }
};
};
template <class T>
auto to_string() {
return std::string{std::experimental::reflect::get_name_v<T>} + '{' +
meta::unpack_sequence_t<
expr<[]<class... Ts> {
auto str = ((std::string{meta::get_name_v<meta::get_type_t<Ts>>} + ':' + meta::get_name_v<Ts> + ',') + ... + std::string{});
str.pop_back();
return str;
}>::template fn, meta::get_data_members_t < T >> {}() + '}';
}
template <class T> auto to_string() {
return []<class... Ts>(boost::mp11::mp_list<Ts...>) {
using std::literals::operator""s;
return meta::get_name_v<T> + "{"s +
boost::algorithm::join(std::vector<std::string>{(
meta::get_name_v<meta::get_type_t<Ts>> +
":"s + meta::get_name_v<Ts>)...},
",") +
"}";
}
(meta::unpack_sequence_t<boost::mp11::mp_list,
meta::get_data_members_t<T>>{});
}
template <typename MO, std::size_t I>
void
field_to_string(std::ostream& out) {
using meta_F = meta::get_element_t<I, MO>;
if(I > 0) out << ",";
out << meta::get_name_v<meta::get_type_t<meta_F>> << ":" << meta::get_name_v<meta_F>;
}
template <typename MO, std::size_t ... I>
void
fields_to_string(std::ostream& out, std::index_sequence<I...>) {
out << "{";
(field_to_string<MO, I>(out), ... );
out << "}";
}
template<class T> auto to_string() {
std::stringstream s{};
s << meta::get_name_v<T>;
using meta_DMs = meta::get_data_members_t<T>;
fields_to_string<meta_DMs>(
s,
std::make_index_sequence<
meta::get_size_v<meta_DMs>
>()
);
return s.str();
}
namespace detail {
template <typename T>
[[nodiscard]] auto get_type_name() -> std::string {
return meta::get_name_v<meta::get_type_t<T>>;
}
template <typename T>
[[nodiscard]] auto get_name() -> std::string {
return meta::get_name_v<T>;
}
template <typename T>
[[nodiscard]] auto get_member_representation() -> std::string {
return get_type_name<T>() + ':' + get_name<T>();
}
template <typename... Ts>
struct get_data_members_impl {
[[nodiscard]] auto operator()() -> std::vector<std::string> {
return {get_member_representation<Ts>()...};
}
};
template <typename T>
[[nodiscard]] auto get_data_members() -> std::vector<std::string> {
return meta::unpack_sequence_t<get_data_members_impl,
meta::get_data_members_t<T>>{}();
}
} // namespace detail
template <class T>
[[nodiscard]] auto to_string() {
return detail::get_name<T>() + '{' +
boost::algorithm::join(detail::get_data_members<T>(), ",") + '}';
}