Skip to content

Latest commit

 

History

History
336 lines (278 loc) · 10.6 KB

255.md

File metadata and controls

336 lines (278 loc) · 10.6 KB
Info

Example

struct foo {
    auto api(int i) -> void;
};

auto main() -> int {
    namespace meta = std::experimental::reflect;
    std::cout << meta::get_size_v<meta::get_member_functions_t<reflexpr(foo)>>; // prints 1
    std::cout << meta::get_name_v<meta::get_element_t<0, meta::get_member_functions_t<reflexpr(foo)>>>; // prints api
    std::cout << meta::get_name_v<meta::get_element_t<0, meta::get_parameters_t<meta::get_element_t<0, meta::get_member_functions_t<reflexpr(foo)>>>>>; // prints i
}

https://compiler-explorer.com/z/ofe3Kfaas

Puzzle

  • Can you implement to_string which reflects member functions for given type?
struct empty {};

struct foo {
    auto api(int i);
    auto api(int i, double d);
};

template<class T> auto to_string(); // TODO

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

  "reflexpr funtions"_test = [] {
    expect("empty{}"s == to_string<empty>());
    expect("foo{api(int i);api(int i, double d);}"s == to_string<foo>());
  };
}

https://godbolt.org/z/xx5ohz7bs

Solutions

template <class...>
struct stringify_parameters;

template <class PList, auto... Is>
struct stringify_parameters<PList, std::index_sequence<Is...>> {
  auto operator()() const {
    const auto type_and_name = [] <class P> {
      return std::string{meta::get_name_v<meta::get_type_t<P>>} + ' ' + meta::get_name_v<P> + ", ";
    };
    std::string s{("" + ... + type_and_name.template operator()<meta::get_element_t<Is, PList>>())};
    if constexpr (sizeof...(Is) > 0) {
      s.pop_back();
      s.pop_back();
    }
    return s;
  }
};

template <class... Ts>
struct stringify_member_funcs {
  auto operator()() const {
    const auto member_func = [] <class T> {
      using Ps = meta::get_parameters_t<T>;
      // why doesn't unpack_sequence_t work on Ps?
      return std::string{meta::get_name_v<T>} + '('
        + stringify_parameters<Ps, std::make_index_sequence<meta::get_size_v<Ps>>>{}()
        + ");";
    };
    return ("" + ... + member_func.template operator()<Ts>());
  }
};

template <class T> auto to_string() {
    using type = meta::get_aliased_t<reflexpr(T)>;
    using member_functions_t = meta::get_member_functions_t<type>;
    return std::string{meta::get_name_v<type>} + '{'
      + meta::unpack_sequence_t<stringify_member_funcs, member_functions_t>{}() + '}';
}

https://godbolt.org/z/zYj8fdYxb

template<class T_> auto to_string() {
    namespace meta = std::experimental::reflect;
    using T = meta::get_aliased_t<reflexpr(T_)>;
    std::stringstream str{};
    str << meta::get_name_v<T> << '{';
    [&]<class... Ts>(std::tuple<Ts...>) {
        const auto f = [&]<class T> {
          str << std::experimental::reflect::get_name_v<T> << '(';
          [&]<class TParams, auto... Ns>(TParams, std::index_sequence<Ns...>) {
              ((str << meta::get_name_v<meta::get_type_t<meta::get_element_t<Ns, TParams>>> << ' ' << meta::get_name_v<meta::get_element_t<Ns, TParams>> << ", "), ...);
              str.seekp(-2, std::ios_base::end);
          }(meta::get_parameters_t<T>{}, std::make_index_sequence<meta::get_size_v<meta::get_parameters_t<T>>>{});
          str << ");";
        };
        (f.template operator()<Ts>(), ...);
    }(meta::unpack_sequence_t<std::tuple, meta::get_member_functions_t<T>>{});
    str << '}';
    return str.str();
}

https://godbolt.org/z/dvzxf4n7n

namespace detail {

template <meta::Object T>
[[nodiscard]] auto get_name() -> std::string {
    return meta::get_name_v<T>;
}

template <meta::Typed T>
[[nodiscard]] auto get_type() -> std::string {
    return meta::get_name_v<meta::get_type_t<T>>;
}

template <meta::FunctionParameter T>
[[nodiscard]] auto get_parameter_representation() -> std::string {
    return get_type<T>() + ' ' + get_name<T>();
}

template <meta::Function T>
[[nodiscard]] auto get_parameter_representations() -> std::vector<std::string> {
    // BUG: unpack_sequence_t doesn't work. If it did, this could be unified
    // with get_member_representations()
    using parameter_list_t = meta::get_parameters_t<T>;
    return
        []<auto... Is>(std::index_sequence<Is...>)->std::vector<std::string> {
        return {get_parameter_representation<
            meta::get_element_t<Is, parameter_list_t>>()...};
    }
    (std::make_index_sequence<meta::get_size_v<parameter_list_t>>{});
}

template <meta::Function T>
[[nodiscard]] auto get_function_representation() -> std::string {
    return get_name<T>() + '(' +
           boost::algorithm::join(get_parameter_representations<T>(), ", ") +
           ')';
}

template <meta::Class T>
[[nodiscard]] auto get_member_representations() -> std::vector<std::string> {
    using sequence_t = meta::unpack_sequence_t<boost::mp11::mp_list,
                                               meta::get_member_functions_t<T>>;
    return []<typename... Ts>(boost::mp11::mp_list<Ts...>)
        ->std::vector<std::string> {
        return {get_function_representation<Ts>()...};
    }
    (sequence_t{});  // TODO: avoid instantiation?
}

template <meta::Class T>
[[nodiscard]] auto get_object_representation() -> std::string {
    const auto members = get_member_representations<T>();
    return get_name<T>() + '{' +
           std::accumulate(std::cbegin(members), std::cend(members),
                           std::string{},
                           [](auto acc, const auto& elem) {
                               acc += elem + ';';
                               return acc;
                           }) +
           '}';
}

}  // namespace detail

template <class T>
auto to_string() {
    return detail::get_object_representation<
        meta::get_aliased_t<reflexpr(T)>>();
}

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

template <typename TParams>
auto parameters_to_string() {
    return []<auto... Is>(std::index_sequence<Is...>) {
        const auto stringify = []<typename TParam> {
            return std::format("{} {}, ",
                meta::get_name_v<meta::get_type_t<TParam>>,
                meta::get_name_v<TParam>);
        };

        auto s = std::string{("" + ... + stringify.template operator()<meta::get_element_t<Is, TParams>>())};
        if constexpr (sizeof...(Is) > 0) {
            s.erase(std::prev(std::cend(s), 2), std::cend(s));
        }
        return s;
    }(std::make_index_sequence<meta::get_size_v<TParams>>{});
};

template<typename... TFuncs>
struct member_functions_to_string {
    auto operator()() const {
        const auto stringify = []<typename TFunc> {
            return std::format("{}({});",
                meta::get_name_v<TFunc>,
                parameters_to_string<meta::get_parameters_t<TFunc>>());
        };
        return ("" + ... + stringify.template operator()<TFuncs>());
    }
};

template <typename T>
auto class_name() {
    using type = meta::get_aliased_t<reflexpr(T)>;
    using member_functions_t = meta::get_member_functions_t<type>;
    return std::format("{}{{{}}}",
        meta::get_name_v<type>,
        meta::unpack_sequence_t<member_functions_to_string, member_functions_t>{}());
}

template<class T> auto to_string() {
    return class_name<T>();

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

template <class T>
decltype(auto) unpack(auto &&initial, auto f) {
  return [&]<class... Ts>(std::tuple<Ts...>)->decltype(auto) {
    return (initial + ... + f.template operator()<Ts>());
  }
  (meta::unpack_sequence_t<std::tuple, T>{});
}

template <class T, template <class> class pack_t>
std::string format_name_and_sequence(const auto &fmt, const auto &f) {
  return std::format(fmt, meta::get_name_v<T>, unpack<pack_t<T>>("", f));
}

template <class T>
auto to_string() {
  const auto parameter = [front = true]<class TParameter> mutable {
    return std::format("{}{} {}", front ? (front = false, "") : ", ",
                       meta::get_name_v<meta::get_type_t<TParameter>>,
                       meta::get_name_v<TParameter>);
  };
  const auto member_function = [=]<class TMemberFunction> {
    return format_name_and_sequence<TMemberFunction, meta::get_parameters_t>(
        "{}({});", parameter);
  };
  using class_t = meta::get_aliased_t<reflexpr(T)>;
  return format_name_and_sequence<class_t, meta::get_member_functions_t>(
      "{}{{{}}}", member_function);
}

https://godbolt.org/z/q6KcWGaK3

template<class Param> auto param_to_string() {
    return std::string{meta::get_name_v<meta::get_type_t<Param>>} + " " + meta::get_name_v<Param>;
}

template<class Params> auto params_to_string() {
    return []<std::size_t... I>(std::index_sequence<I...>){
        return (((I == 0 ? "" : ", ") + param_to_string<meta::get_element_t<I,Params>>()) + ... + "");
    }(std::make_index_sequence<meta::get_size_v<Params>>{});
}

template<class MemFn> auto memfn_to_string() {
    return std::string{meta::get_name_v<MemFn>} + "(" + params_to_string<meta::get_parameters_t<MemFn>>() + ");";
}

template<class MemFns> auto memfns_to_string() {
    return []<std::size_t... I>(std::index_sequence<I...>) {
        return (memfn_to_string<meta::get_element_t<I, MemFns>>() + ... + "");
    }(std::make_index_sequence<meta::get_size_v<MemFns>>{});
}

template<class T> auto to_string() {
    using Aliased = meta::get_aliased_t<reflexpr(T)>;
    return std::string{meta::get_name_v<Aliased>} + "{" + memfns_to_string<meta::get_member_functions_t<Aliased>>() + "}";
}

https://godbolt.org/z/MjMsT5hqf

template<class ...Ts>
struct FunArgString {
     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()-2);
      return str;
    }
};

template<class ...T>
struct MemFunString {
    auto operator()(char sep) {
        auto wrap = []<typename P>(P) { return "(" + meta::unpack_sequence_t<FunArgString, meta::get_parameters_t<P>>{}() +")";   };
        std::string str = ( (std::string{meta::get_name_v<T>}+ wrap(T{}) + std::string{sep}) + ...  +std::string{});
        return str;
    }
};

template<class T> auto to_string() {
    using meta_T = meta::get_aliased_t<reflexpr(T)>;
    using meta_T_funcs = meta::get_member_functions_t<meta_T>;
    std::string ret = meta::get_name_v<meta_T>;
    ret += "{";
    ret += meta::unpack_sequence_t<MemFunString, meta::get_member_functions_t<meta_T>>{}(';');
    ret += "}";
    return ret;
}

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