Skip to content

Latest commit

 

History

History
179 lines (152 loc) · 4.62 KB

256.md

File metadata and controls

179 lines (152 loc) · 4.62 KB
Info

Example

template <class T> auto to_string() {
  const auto t = get_aliased(mirror(T));
  std::stringstream str{};
  str << get_name(t) << '{';
  for_each(get_enumerators(t),
    [&str](auto o) { str << get_name(o) << '=' << get_constant(o) << ';'; }
  );
  str << '}';
  return str.str();
}

enum Weekdays {
  Mon = 2,
  Tue = 3,
  Wed = 4,
  Thu = 5,
  Fri = 6,
  Sat = 1,
  Sun = 0
};

int main() {
  std::cout << to_string<Weekdays>(); // prints Weekdays{Mon=2;Tue=3;Wed=4;Thu=5;Fri=6;Sat=1;Sun=0;}
}

https://godbolt.org/z/hvz6W6szW

Puzzle

  • Can you implement to_string function which returns string representation for given type: type_name{field_type:field_name=value,...} by applying mirror/value based interface?
template <class T>
auto to_string(const T& t); // TODO

struct empty {};

struct foo {
  int i;
  double d;
};

struct bar {
  foo f;
  bool b;
};

int main() {
  using namespace boost::ut;
  using std::literals::string_literals::operator""s;

  "mirror to_string"_test = [] {
    expect("empty{}"s == to_string(empty{}));
    expect("foo{int:i=1,double:d=0.2}"s == to_string(foo{.i = 1, .d = .2}));
    expect("foo{int:i=0,double:d=4.2}"s == to_string(foo{.i = {}, .d = 4.2}));
    expect("bar{foo{int:i=2,double:d=0.2},bool:b=1}"s == to_string(bar{.f = {.i = 2, .d = .2}, .b = true}));
  };
}

https://godbolt.org/z/aMh5zh51s

Solutions

template <class T>
auto to_string(const T& t) {
  const auto ty = get_aliased(mirror(T));
  std::stringstream str{};
  str << get_name(ty) << '{';
  bool first = true;
  for_each(get_data_members(ty),
    [&](auto m) {
      if (not first) {
        str << ',';
      } else {
        first = false;
      }
      const auto& val = get_value(m, t);
      if constexpr (std::is_class_v<std::remove_cvref_t<decltype(val)>>) {
        str << to_string(val);
      } else {
        str << get_name(get_type(m)) << ':' << get_name(m) << '=' << val;
      }
    });
  str << '}';
  return str.str();
}

https://godbolt.org/z/vjn5K94sa

template <class T>
[[nodiscard]] auto to_string(const T& object) -> std::string {
    const auto mirrored_type = get_aliased(mirror(T));
    std::stringstream member_stream{};
    for_each(get_data_members(mirrored_type), [&](const auto member) -> void {
        const auto value = get_value(member, object);
        using value_t = std::remove_cvref_t<decltype(value)>;
        if constexpr (std::is_class_v<value_t>) {  // Why doesn't
                                                   // is_class(member) work?
            member_stream << to_string(value);
        } else {
            member_stream << get_name(get_type(member)) << ':'
                          << get_name(member) << '=' << value;
        }
        member_stream << ',';
    });
    auto member_string = member_stream.str();
    if (std::size(member_string) > 0) {
        member_string.pop_back();
    }

    return std::string{get_name(mirrored_type)} + '{' + member_string + '}';
}

https://jonathan.godbolt.org/z/qGx1cGEGs

template <typename S>
auto to_string(const S& x) {
  std::stringstream str{};
  str << get_name(get_aliased(mirror(S)));
  str << '{';
  bool first = true;
  for_each(get_data_members(get_aliased(mirror(S))),
    [&](auto mo) {
        if constexpr(std::is_class_v<std::remove_cvref_t<decltype(get_value(mo,x))>>)
            str << to_string(get_value(mo,x)) << ",";
        else {
            if (first) first = false;
            else str << ",";
            str << get_name(get_type(mo)) << ":" << get_name(mo) << "=" << get_value(mo, x);
        }
    });
  str << '}';
  return str.str();
}

https://godbolt.org/z/4qaxnWo4K

template <class T>
auto to_string(const T& t) {
    const auto t_mirror = get_aliased(mirror(T));
    std::stringstream str{};
    str << get_name(t_mirror) << "{";
    std::string sep = "";
    for_each(get_data_members(t_mirror),
            [&] (auto member) {
                auto value = t.*get_pointer(member);
                if constexpr (requires {str << value;}) {
                    str << sep << get_name(get_type(member)) << ":" << get_name(member)
                        << "=" << value;
                } else {
                    str << to_string(value);
                }
                sep = ",";
             });

    str << "}";
    return str.str();
}

https://godbolt.org/z/bs6hhWfKd