Skip to content

Latest commit

 

History

History
301 lines (233 loc) · 9.05 KB

208.md

File metadata and controls

301 lines (233 loc) · 9.05 KB
Info

Example

namespace detail {
  template<class...>
  struct type_defaults{};

  template<template<class...> class T, class... Ts>
  struct type_defaults<T<Ts...>>{
    using type = std::tuple<Ts...>;
  };
} // namespace detail

template<template<class...> class T>
using type_defaults_t = typename detail::type_defaults<T<>>::type;

template<class = int> struct foo{};
static_assert(std::is_same_v<std::tuple<int>, type_defaults_t<foo>>);

template<class TQuant = class Quant, class TLab = class Lab> struct bar{};
static_assert(std::is_same_v<std::tuple<Quant, Lab>, type_defaults_t<bar>>);

https://godbolt.org/z/TWPo6j

Puzzle

  • Can you implement rebind_defaults_t type trait which rebinds template arguments depending on provided bindings... (bind<From, To>)?
template<class...> struct bind;

template<template<class...> class T, class... Ts>
using rebind_defaults_t = /*TODO*/T<Ts...>;

template<class = int> struct foo{};
static_assert(std::is_same_v<foo<>, rebind_defaults_t<foo>>);
static_assert(std::is_same_v<foo<int>, rebind_defaults_t<foo>>);
static_assert(std::is_same_v<foo<double>, rebind_defaults_t<
  foo,
  bind<int, double>
>>);

template<class TQuant = class Quant, class TLab = class Lab> struct bar{};
static_assert(std::is_same_v<bar<Quant, Lab>, rebind_defaults_t<bar>>);
static_assert(std::is_same_v<bar<int, Lab>, rebind_defaults_t<
  bar,
  bind<Quant, int>
>>);
static_assert(std::is_same_v<bar<Quant, double>, rebind_defaults_t<
  bar,
  bind<class Lab, double>
>>);
static_assert(std::is_same_v<bar<int, double>, rebind_defaults_t<
  bar,
  bind<Quant, int>,
  bind<Lab, double>
>>);
static_assert(std::is_same_v<bar<int, double>, rebind_defaults_t<
  bar,
  bind<Lab, double>,
  bind<Quant, int>
>>);

https://godbolt.org/z/se4rc7

Solutions

template <class T, class U> struct bind {};

namespace detail {
template <class... Ts> struct rebind_map : Ts... {};

template <class T, class U> constexpr auto rebind_lookup(const bind<T, U>&) -> U;
template <class T> constexpr auto rebind_lookup(...) -> T;

template <class TMap>
struct rebinder {
  template <class...> struct rebind_types{};

  template <template<class...> class T, class... Ts>
  struct rebind_types<T<Ts...>> {
    using type = T<decltype(rebind_lookup<Ts>(std::declval<TMap>()))...>;
  };
};
} // namespace detail

template <template<class...> class T, class... Ts>
using rebind_defaults_t =
  typename detail::rebinder<detail::rebind_map<Ts...>>::template rebind_types<T<>>::type;

https://godbolt.org/z/PY49f8

namespace detail {
  template<class...> struct type_defaults{};

  template<template<class...> class T, class... Ts>
  struct type_defaults<T<Ts...>>{
    using type = std::tuple<Ts...>;
  };
} // namespace detail

template<template<class...> class T>
using type_defaults_t = typename detail::type_defaults<T<>>::type;

template<class...> struct bind;
template<class L, class T > struct unbind;
template<class L, class T1,class T2 > struct unbind<L, bind<T1,T2>>
{
    using type = boost::mp11::mp_replace<L,T1,T2>;
};
template<class L, class T > using unbind_t = typename unbind<L,T>::type;
template<template<class...> class T, class... Ts>
using rebind_defaults_t = boost::mp11::mp_apply<T,boost::mp11::mp_fold<boost::mp11::mp_list<Ts...>,type_defaults_t<T>,unbind_t>>;

https://godbolt.org/z/K8W8h4

namespace detail {
    template<class...> struct type_defaults {};

    template<template<class...> class T, class... Ts>
    struct type_defaults<T<Ts...>> {
        using type = T<Ts...>;
    };

    template<template<class...> class T>
    using type_defaults_t = typename detail::type_defaults<T<>>::type;

    template<class T> struct unhandled {
        using type = T;
    };

    template<class T> struct handled {
        using type = T;
    };

    template<class T>
    using trait_t = typename T::type;
} // namespace detail

template<class From, class To> struct bind {
    template<class T>
    using fn = mp11::mp_if<
        mp11::mp_same<T, detail::unhandled<From>>,
        detail::handled<To>,
        T>;
};

template<template<class...> class T, class... Ts>
using rebind_defaults_t = mp11::mp_transform_q<
    mp11::mp_compose_q<
        mp11::mp_quote<detail::unhandled>,
        Ts...,
        mp11::mp_quote<detail::trait_t>>,
    detail::type_defaults_t<T>>;

https://godbolt.org/z/n8rvso

namespace detail {
  template<class...>
  struct type_defaults{};

  template<template<class...> class T, class... Ts>
  struct type_defaults<T<Ts...>>{
    using type = std::tuple<Ts...>;
  };

  template<template<class...> class, class...> struct rebind_defaults{};
  template<template<class...> class T, class... TIfs, class... TImpls>
  struct rebind_defaults<T, std::tuple<TIfs...>, TImpls...>{
    template<class U, class> struct rebind { using type = U; };
    template<class U, template<class, class> class TBind, class TIf, class TImpl> struct rebind<U, TBind<TIf, TImpl>> { using type = TImpl; };
    using type = T<typename rebind<TIfs, boost::mp11::mp_map_find<boost::mp11::mp_inherit<TImpls...>, TIfs>>::type...>;
  };

} // namespace detail

template<template<class...> class T>
using type_defaults_t = typename detail::type_defaults<T<>>::type;

template<template<class...> class T, class... Ts>
using rebind_defaults_t = typename detail::rebind_defaults<T, type_defaults_t<T>, Ts...>::type;

https://godbolt.org/z/Yrer9f

namespace detail {
  template<class...> struct type_defaults{};

  template<template<class...> class T, class... Ts>
  struct type_defaults<T<Ts...>>{
    using type = std::tuple<Ts...>;
  };
} // namespace detail

template<template<class...> class T>
using type_defaults_t = typename detail::type_defaults<T<>>::type;

template<class...> struct bind;

template<class...> struct rebind_next;
template<class D> struct rebind_next<D> { using type = D;  };

template<class D, class R, class ...Ms, class...Rs>
struct rebind_next<D, bind<D,R>, bind<Ms,Rs>...> { using type = R; };
template<class D, class M, class R, class ...Ms, class... Rs>
struct rebind_next<D, bind<M,R>, bind<Ms,Rs>...> {
    using type = typename rebind_next<D, bind<Ms,Rs>...>::type;
};

template<class...> struct list;
template<class ...Fs, class D, class ...Ds, class...Ms, class ...Rs>
struct rebind_next< list<Fs...>, list<D, Ds...>, bind<Ms, Rs>...> {
    using type = typename rebind_next< list<Fs..., typename rebind_next<D, bind<Ms, Rs> ...>::type >, list<Ds...>, bind<Ms,Rs>...>::type;
};
template<class ...Fs, class D, class...Ms, class ...Rs>
struct rebind_next< list<Fs...>, list<D>, bind<Ms,Rs>...> {
    using type = list<Fs..., typename rebind_next<D, bind<Ms,Rs>...>::type>;
};


template<template<class...> class N, class O> struct rename;
template<template<class...> class N , template<class...> class O, class ...Es>
struct rename< N, O<Es...>> { using type = N<Es...>;  };

template<class...> struct rebind_defaults;
template<template<class...> class T, class... Ds, class ...Ms, class... Rs>
struct rebind_defaults<T<Ds...>, bind<Ms, Rs>...> {
    using rebound_list = typename rebind_next< list<>, list<Ds...>, bind<Ms,Rs>...>::type;
    using type = typename rename< T, rebound_list>::type;
};

template<template<class...> class T, class... Ts>
using rebind_defaults_t = typename rebind_defaults<T<>, Ts...>::type;

https://godbolt.org/z/rKPG9h

namespace detail {
  template<class...> struct type_defaults{};

  template<template<class...> class T, class... Ts>
  struct type_defaults<T<Ts...>>{
    using type = std::tuple<Ts...>;
  };

  template<class T, class>
  struct process_bind {
    using type = T;
  };
  template<class T, template<class, class> class TBind, class TReplace>
  struct process_bind<T, TBind<T, TReplace>> {
    using type = TReplace;
  };

  template<class T, class TBind>
  using process_bind_t = process_bind<T, TBind>::type;

  template<template<class...> class, class...>
  struct rebind {};
  template<template<class...> class TContainer, template<class...> class TDefaultContainer, class... TDefaults, class... TBinds>
  struct rebind<TContainer, TDefaultContainer<TDefaults...>, TBinds...> {
    using binds_t = boost::mp11::mp_list<TBinds...>;
    using type = TContainer<process_bind_t<TDefaults, boost::mp11::mp_map_find<binds_t, TDefaults>>...>;
  };

  namespace test {
    template<class...> struct test {};

    static_assert(std::is_same_v<process_bind_t<int, test<int, float>>, float>);
    static_assert(std::is_same_v<process_bind_t<int, test<long, float>>, int>);
  }
} // namespace detail

template<template<class...> class T>
using type_defaults_t = typename detail::type_defaults<T<>>::type;

template<class...> struct bind;
template<template<class...> class T, class... TBinds>
using rebind_defaults_t = detail::rebind<T, type_defaults_t<T>, TBinds...>::type;

https://godbolt.org/z/a88PzG