254.md

September 5, 2022 ยท View on GitHub

Info

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
}

https://godbolt.org/z/x55GPdTxE

Puzzle

  • Can you implement to_string function 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)>());
  };
}

https://godbolt.org/z/vK9ME7nWc

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>>{}() + '}';
}

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

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();
}

https://godbolt.org/z/xc8nevqha

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();
}

https://godbolt.org/z/7Y5f77zza

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;
}

https://godbolt.org/z/q9vErrzeb

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>>{}());
}

https://godbolt.org/z/1PGbeMq69

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 >> {}() + '}';
}

https://godbolt.org/z/3sdvq69s1

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>>{});
}

https://godbolt.org/z/xf74M918h

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();
}

https://godbolt.org/z/f4x48noxY

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>(), ",") + '}';
}

https://jonathan.godbolt.org/z/57xdeWKss