Du Suchst Übung!?



  • templer schrieb:

    Nice. Kommst du auch auf die Lösung mit using, die keine extra struct benötigt?

    Klar:

    template <typename... Ts> struct all_equal;
    template <typename T, typename... Ts> struct all_equal<T, Ts...>
    {
      template<typename T2> using all_equal_impl = std::is_same<T, T2>;
      static constexpr bool value = tmpalg::all_of<tmpalg::type_list<Ts...>, all_equal_impl >::value;
    };
    template <> struct all_equal<> : std::true_type {};
    

    Edit: Ein bisschen eingerückt komme ich auf 65 :p (Edit²:) Mit langem Namen!



  • 👍



  • Eine weitere Aufgabe hab ich noch eingesendet:

    Gegeben sind eine constexpr Funktion f und eine Zahl N
    Quellcode ausblenden C-Code

    constexpr long long f(int n); // z.B. die Fakultätsfunktion
    const int N = 20; // Variabel, aber zur Compile-Zeit bekannt
    

    Deine Aufgabe ist es, ein Lookup-Table der Grösse N mit zur Compile-Zeit berechneten Werten zu füllen:

    constexpr std::array<decltype(f(0)), N> table = ... // die Punkte sind zu ersetzen
    for (int i=0; i<N; ++i) assert(table[i] == f(i)); // diese Werte müssen darin sein
    

    Sehr wahrscheinlich ist es nötig, weitere Funktionen und Klassen zu definieren, das ist alles erlaubt, solange das Table constexpr bleibt.

    Wünschenswert, aber nicht notwendig, wäre es, wenn f und N in "..." irgendwie als Parameter übergeben werden und nicht hardgecodet sind.

    Vor einem halben Jahr hab ich mal sowas gemacht.



  • Hier ein Filter ohne merge/cons/concat, dafür mit expliziter Rekursion (also quasi ein implizites merge/cons/concat):

    template <typename T> struct identity_ { using type = T; };
      template <typename, typename, template <typename> class> struct filter_;
      template <typename... L, typename M, typename... R, template <typename> class Pred>
      struct filter_<type_list<L...>, type_list<M, R...>, Pred>
        : std::conditional<Pred<M>::value,
                           filter_<type_list<L..., M>, type_list<R...>, Pred>,
                           filter_<type_list<L...>, type_list<R...>, Pred> >::type {};
      template <typename TL, template <typename> class Pred>
      struct filter_<TL, type_list<>, Pred> : identity_<TL> {};
      template <typename TL, template <typename> class Pred=identity>
      using filter = typename filter_<type_list<>, TL, Pred>::type;
    


  • 1500 Punkte ... Platz 3



  • Verdammt! Zehn Punkte vor Platz 2! 😡



  • Hehe, camper hat sich also doch angemeldet! 😃


  • Mod

    Ich habe jetzt noch ein filter ohne merge&co & expliziter rekursion im Algorithmus (die Rekursion steckt hier wie üblich in make_index_list und derived_tag).. Funktioniert aber leider wieder nur mit clang.

    #include <type_traits>
    
    namespace tmpalg {
      template <typename T>
      struct identity_ {
        using type = T;
      };
      template <typename T>
      using identity = T;
    
      template <typename... T>
      struct type_list
        : identity_<type_list<T...>> {};
    
      template <int... i>
      struct index_list
        : identity_<index_list<i...>> {};
    
      template <typename T>
      struct true_pred
        : std::true_type {};
    
      template <int N, typename = index_list<>>
      struct make_index_list_;
      template <int N, typename T = index_list<>>
      using make_index_list = typename make_index_list_<N, T>::type;
      template <int N, int... i>
      struct make_index_list_<N, index_list<i...>>
        : make_index_list<N-1, index_list<0, 1+i...>> {};
      template <int... i>
      struct make_index_list_<0, index_list<i...>>
        : index_list<i...> {};
    
      template <int I>
      struct tag {};
    
      template <typename TL>
      struct size_;
      template <typename TL>
      using size = typename size_<TL>::type;
      template <typename... T>
      struct size_<type_list<T...>>
        : std::integral_constant<int, sizeof...(T)> {};
    
      template <typename TL, template <typename> class F>
      struct transform_;
      template <typename TL, template <typename> class F>
      using transform = typename transform_<TL, F>::type;
      template <typename... T, template <typename> class F>
      struct transform_<type_list<T...>, F>
        : type_list<F<T>...> {};
    
      template <int I, bool b, typename T>
      struct helper
        : std::integral_constant<bool, b>
      {
        friend identity_<T> at_adl(tag<I>, helper);
      };
    
      template <typename TL, template <typename> class Pred = true_pred, typename I = make_index_list<size<TL>::value>>
      struct apply_pred_;
      template <typename... T, template <typename> class Pred, int... i>
      struct apply_pred_<type_list<T...>, Pred, index_list<i...>>
        : helper<i, Pred<T>::value, T>... {};
    
      template <typename TL, int N>
      struct at_
        : identity_<typename decltype(at_adl(tag<N>{}, apply_pred_<TL>{}))::type> {};
      template <typename TL, int N>
      using at = typename at_<TL, N>::type;
    
      template <int I>
      struct indexed_value
      {
        constexpr indexed_value(int v) : value(v) {}
        int value;
      };
    
      template <typename TL, template <typename> class Pred = true_pred, typename I = make_index_list<size<TL>::value>>
      struct apply_pred;
      template <typename... T, template <typename> class Pred, int... i>
      struct apply_pred<type_list<T...>, Pred, index_list<i...>>
        : apply_pred_<type_list<T...>, Pred, index_list<i...>>, indexed_value<-1>, indexed_value<i>...
      {
        constexpr apply_pred() : indexed_value<-1>(0), indexed_value<i>(get<i-1>()+Pred<T>::value)... {}
        constexpr int count() const { return get<sizeof...(i)-1>(); }
        template <int I> constexpr int get() const { return indexed_value<I>::value; }
      };
    
      template <int I>
      struct derived_tag : derived_tag<I-1> {};
      template <>
      struct derived_tag<0> {};
    
      template <typename TL, template <typename> class Pred, typename I = make_index_list<size<TL>::value>, typename J = make_index_list<apply_pred<TL, Pred>().count()>>
      struct filter_;
      template <typename TL, template <typename> class Pred = true_pred>
      using filter = typename filter_<TL, Pred>::type;
      template <typename TL, template <typename> class Pred, int... i, int... j>
      struct filter_<TL, Pred, index_list<i...>, index_list<j...>>
      {
        static constexpr apply_pred<TL, Pred> x{};
        template <int x, int y>
        struct ordered_pair
        {
          friend constexpr int find_first(int derived_tag<x>::*, tag<y>, ordered_pair) { return x; }
        };
        struct bimap
          : ordered_pair<i, x.template get<i>()>... {};
        using type = type_list<at<TL,find_first(static_cast<int derived_tag<0>::*>(nullptr), tag<j+1>(), bimap())>...>;
      };
    
      template <typename TL, template <typename> class Pred = true_pred>
    //  using all_of = std::integral_constant<bool, !std::is_base_of<std::false_type, apply_pred_<TL, Pred>>::value>;
      using all_of = std::integral_constant<bool, apply_pred<TL, Pred>().count() == size<TL>::value>;
    
      template <typename TL, template <typename> class Pred = true_pred>
    //  using any_of = std::is_base_of<std::true_type, apply_pred_<TL, Pred>>;
      using any_of = std::integral_constant<bool, apply_pred<TL, Pred>().count() != 0>;
    
      template <typename TL, template <typename> class Pred = true_pred>
    //  using none_of = std::integral_constant<bool, !std::is_base_of<std::true_type, apply_pred_<TL, Pred>>::value>;
      using none_of = std::integral_constant<bool, apply_pred<TL, Pred>().count() == 0>;
    }
    


  • Yes! Zweiter!

    Edit: Ach menno. Und camper hat wieder einen Bosscode. 😞 😞



  • Alle Achtung camper, auch dein at ist sehr elegant.



  • Ich habe fast die lookup-Table fertig... 🙂
    Edit: Ja, campers Code ist fast perfekt.



  • So, fertig! Ich frag mal gar nicht sondern Poste:

    #include <array>
    
    typedef uint_least64_t fac_result_t;
    typedef uint8_t fac_of_t;
    fac_of_t constexpr N = 20;
    typedef std::array<fac_result_t, N> array_t;
    
    constexpr fac_result_t fak(fac_of_t n) { return n > 1 ? fak(n-1)*n : 1; }
    
    /// *** Hier wird es interessant:
    template<fac_of_t still, fac_result_t F(fac_of_t), fac_of_t ... args> struct table_impl
    { static array_t constexpr table = table_impl<still - 1, F, args..., N - still>::table; };
    template<fac_of_t ... args, fac_result_t F(fac_of_t)> struct table_impl<0, F, args...>
    { static array_t constexpr table { F(args)... }; };
    /// ***
    array_t constexpr table = table_impl<N, fak>::table;
    
    #include <cassert>
    int main()
    {
        for (unsigned i=0; i<N; ++i)
            assert(table[i] == fak(i));
    }
    

    Die Lösung ist bereits eingereicht 🙂



  • Verbesserungsvorschlag: Verzichte auf die explizite Rekursion unter Benutzung von campers make_index_list.


  • Mod

    Meine Lösung zu all_equal

    template <typename... Ts> struct all_equal;
    template <typename T, typename... Ts> struct all_equal<T, Ts...>
      : std::is_same<tmpalg::type_list<T, Ts...>, tmpalg::type_list<Ts..., T>> {};
    template <> struct all_equal<> : std::true_type {};
    

    (nicht ganz das Geforderte).

    Edit: Wenn ich recht darüber nachdenke, kann man so dann auch all_of&co schreiben:

    template <typename TL, template <typename> class Pred>
    struct all_of;
    template <typename... T, template <typename> class Pred>
    struct all_of<type_list<T...>>
      : all_equal<std::true_type, std::integral_constant<bool, Pred<T>::value>...> {};
    
    template <typename TL, template <typename> class Pred>
    struct none_of;
    template <typename... T, template <typename> class Pred>
    struct none_of<type_list<T...>>
      : all_equal<std::false_type, std::integral_constant<bool, Pred<T>::value>...> {};
    
    template <typename TL, template <typename> class Pred>
    struct any_of
      : std::integral_constant<bool, !none_of<TL, Pred>::value> {};
    

    mit minimalem Instantiierungsaufwand.



  • template <typename... Ts> struct all_equal; 
    template <typename T, typename... Ts> struct all_equal<T, Ts...> 
      : std::is_same<tmpalg::type_list<T, Ts...>, tmpalg::type_list<Ts..., T>> {}; 
    template <> struct all_equal<> : std::true_type {};
    

    😮 Das ist genial!



  • Camper, hast du auch eine Lösung für #40 ohne merge&co & explizite Rekursion?

    template <typename... T> struct type_list { typedef type_list type; };
    template <typename T> struct identity_ { typedef T type; };
    
    template <template<typename>class A, typename TL> struct transform_32;
    template <template<typename>class A, typename... T>
    struct transform_32<A, type_list<T...> > : type_list<typename A<T>::type...> {};
    
    template <typename TL> struct head;
    template <typename T, typename... Ts> struct head<type_list<T, Ts...> >
      : identity_<T> {};
    
    template <typename TL> struct tail;
    template <typename T, typename... Ts> struct tail<type_list<T, Ts...> >
      : identity_<type_list<Ts...> > {};
    
    template <template <typename...> class F, typename TL> struct call;
    template <template <typename...> class F, typename... Ts>
    struct call<F, type_list<Ts...> > : identity_<typename F<Ts...>::type> {};
    
    template <typename T, typename TL> struct cons;
    template <typename T, typename... Ts>
    struct cons<T, type_list<Ts...> > : identity_<type_list<T, Ts...> > {};
    
    template <template <typename...> class F, typename... TLs>
    struct transform_;
    template <template <typename...> class F, typename... TLs>
    using transform = typename transform_<F, TLs...>::type;
    
    template <template <typename...> class F, typename... TLs>
    struct transform_<F, type_list<>, TLs...> : identity_<type_list<> > {};
    
    template <template <typename...> class F>
    struct transform_<F> : identity_<type_list<> > {};
    
    template <template <typename...> class F, typename TL>
    struct call_transform {
      template <typename... TLs> using trans = transform<F, TLs...>;
      using type = typename call<trans, TL>::type;
    };
    
    template <template <typename...> class F, typename... TLs>
    struct transform_
      : identity_<typename cons<typename call<F, typename transform_32<head, type_list<TLs...> >::type>::type,
                                typename call_transform<F, typename transform_32<tail, type_list<TLs...> >::type>::type>::type
                  > {};
    

  • Mod

    Ich habe mir bisher nicht die Mühe gemacht, selbst eine Lösung zu erstellen.
    Eine Merge ohne Rekursion ist allerdings möglich, wenn man at etwas verallgemeinert...
    Ich schreibs mal auf, wenn Sone seine Lösung abgeliefert hat.



  • Ich schreibs mal auf, wenn Sone seine Lösung abgeliefert hat.

    Sone hat Fragen zur Aufgabe.
    Und zwar, nach welchen Kriterien soll entschieden werden ob alle Elemente einer Typliste zu einem neuen Element der neuen TL verschmelzen, oder ob jedes Element jeder Typliste zur neuen Typliste dazuzählt?


  • Mod

    Verstehe die Frage nicht. Hast du ein Beispiel?



  • Unter Benutzung von Campers make_index_list und den Helfern at , size und identity_ aus #32:

    template <template <typename...> class F, typename TL> struct call;
    template <template <typename...> class F, typename... Ts>
    struct call<F, type_list<Ts...> > : identity_<typename F<Ts...>::type> {};
    
    template <template <typename...> class F, typename I, typename... TLs>
    struct transform_;
    template <template <typename...> class F, typename... TLs>
    using transform = typename transform_<F, make_index_list<size<at<type_list<TLs...>, 0> >::value>, TLs...>::type;
    template <template <typename...> class F, int... I, typename... TLs>
    struct transform_<F, index_list<I...>, TLs...> {
      template <int i> struct tlat : identity_<type_list<at<TLs, i>...> > {};
      using type = type_list<typename call<F, typename tlat<I>::type>::type...>;
    };
    

    (Mich wundert, dass wenn man Zeile 11 durch template <int i> using tlat = identity_<type_list<at<TLs, i>...> >; ersetzt, sowohl GCC als auch Clang den Code ablehnen, weil sie Pack Expansion über beide Template Parameter zu machen versuchen.)


Anmelden zum Antworten