Probleme bei Tutorial (Programm zur Auflistung aller Primzahlen von 1 bis 100)
-
Kellerautomat schrieb:
sie sind einfach eine Vereinfachung für Typlisten, wie aus dem Alexandrescu bekannt.
Das ist Sepp sicherlich bekannt. Aber es sind generische Typlisten

-
Was soll denn bitte eine generische Typliste sein?
-
Kellerautomat schrieb:
Was soll denn bitte eine generische Typliste sein?
Was ich meine ist folgendes: Ich dachte, du meinst, man kann statt
template<typename ...c> void func(//.....Auch gleich das aufzurufende einsetzen.
template<char a, size_t s, char b> void func(//...In diesem Fall ist aber (ich weiß nicht ob das Wort hier passt) oberes generischer, nicht?
-
Keine Ahnung, wovon du redest. Das hat damit überhaupt nichts zu tun. Hast du den Alexandrescu überhaupt gelesen? Falls nein -> großer Fehler.
-
SeppJ schrieb:
Ei, das ist wirklich übel hart. Da bin ich mir selbst nach einigem Nachdenken nicht sicher, ob das überhaupt geht.
Bitteschön.
#include <iostream> #include <type_traits> template <bool B> struct bool_ : std::integral_constant<bool, B> {}; template <unsigned I> struct unsigned_ : std::integral_constant<unsigned, I> {}; template <typename A, typename B> struct dividable : bool_<A::value % B::value == 0> {}; template <typename A, typename B> struct or_ : bool_<A::value || B::value> {}; template <typename I> struct increment : unsigned_<I::value + 1> {}; template <typename A, typename B> struct squared_less_equal : bool_<(A::value * A::value <= B::value)> {}; template <typename A> struct not_ : bool_<!A::value> {}; template < template <typename, typename> class Func, typename Arg1 > struct bind1st { template <typename Arg2> struct binder1st : Func<Arg1, Arg2> {}; }; template < template <typename, typename> class Func, typename Arg2 > struct bind2nd { template <typename Arg1> struct binder2nd : Func<Arg1, Arg2> {}; }; template < typename Init, template <typename> class Cond, template <typename> class Next, template <typename> class Do, template <typename, typename> class Combine, typename Else > struct for_ : std::conditional < Cond<Init>::value, typename std::conditional < Cond<Next<Init>>::value, Combine < Do<Init>, for_<Next<Init>, Cond, Next, Do, Combine, Else> >, Do<Init> >::type, Else >::type {}; template <unsigned I> struct is_prime : not_ < for_ < unsigned_<2>, bind2nd<squared_less_equal, unsigned_<I>>::template binder2nd, increment, bind1st<dividable, unsigned_<I>>::template binder1st, or_, bool_<true> > > {}; template <> struct is_prime<2> : bool_<true> {}; template <> struct is_prime<3> : bool_<true> {}; template <char... S> struct string : std::identity<string<S...>> { static char const c_str[]; }; template <char... S> char const string<S...>::c_str[] = { S..., 0 }; template <typename S1, typename S2> struct append : append<typename S1::type, typename S2::type> {}; template <char... S1, char... S2> struct append<string<S1...>, string<S2...>> : string<S1..., S2...> {}; template <unsigned I> struct to_string : std::conditional < I < 10, string<I + '0'>, append<to_string<I / 10>, string<I % 10 + '0'>> >::type {}; template <typename A, typename B> struct less : bool_<(A::value < B::value)> {}; template <typename I> struct to_string_if_prime : std::conditional < is_prime<I::value>::value, append<to_string<I::value>, string<' '>>, string<> > {}; template <unsigned N> struct primes_below : for_ < unsigned_<0>, bind2nd<less, unsigned_<N>>::template binder2nd, increment, to_string_if_prime, append, string<> > {}; int main() { std::cout << primes_below<100>::type::c_str << '\n'; }Man möge mir das überschüssige Whitespace am Ende verzeihen.
-
Kellerautomat schrieb:
http://ideone.com/tswvnMan möge mir das überschüssige Whitespace am Ende verzeihen.
Sehr schöne Buchlösung, verliert aber Stilpunkte wegen for_

Jetzt noch bitte eine Variante, bei der die Tiefe der rekursiven Instantiierung beschränkt ist auf sagen wir 10.
-
Kellerautomat schrieb:
Keine Ahnung, wovon du redest. Das hat damit überhaupt nichts zu tun. Hast du den Alexandrescu überhaupt gelesen? Falls nein -> großer Fehler.
Ja, hast Recht. Seh ich mir mal an.
-
Ist std::identity() das neue void main()?
SCNR

-
Furble Wurble schrieb:
Ist std::identity() das neue void main()?
SCNR

?????
Was sagt eigentlich SeppJ dazu?

-
Ich schlage
#!/usr/bin/make -f foo: foo.cc $(CXX) $(CXXFLAGS) -o $@ $+ primes.inl: echo \"$(shell primes 1 100)\\n\" > $@ foo.cc: primes.inlin der Makefile und
#include <iostream> int main() { std::cout << #include "primes.inl" ; }als foo.cc vor.
-
Kellerautomat schrieb:
Was sagt eigentlich SeppJ dazu?

Zu was genau? Dein Programm? Cool.
Ganz schön viel Mühe. Die Kritik ist doch Pillepalle.Jetzt müsstest du aber natürlich eigentlich noch die variadic templates durch klassische Typlisten ersetzen, da du vorher so groß davon geredet hast.

-
Ich hab' mir das schon überlegt.
Bis zur Erzeugung des Strings sehe ich kein echtes Problem (hab's nicht implementiert, aber müsste IMO ganz gut gehen -- wenn auch die Compilezeiten sicher massiv ansteigen im Vergleich zur variadic-template Variante).Nur mir will einfach keine Möglichkeit einfallen ein grosses
char-Array zu erzeugen ohne dabei Overloads für 1 ... N Elemente zu schreiben.
Und naja... so ein String kann schonmal lange werden. Und ein Klassentemplate mit 1000 spezialisierungen... pfuh. Hardcore
Dummerweise kann man ja nicht ein
char[N]Array mit einem anderenchar[N-1]Array + einem einzelnencharinitialisieren, ohne explizit{ a[0], a[1] a[2], ... a[N-1], next }zu schreiben.
-
Z.B. so:
#include <array> #include <iostream> #include <type_traits> struct list_end {}; template <typename Head, typename Tail> struct typelist {}; template <unsigned I> struct unsigned_ : std::integral_constant<unsigned, I> {}; template <char C> struct char_ : std::integral_constant<char, C> {}; template <typename> struct length; template <typename Head, typename Tail> struct length<typelist<Head, Tail>> : unsigned_<1 + length<Tail>::value> {}; template <typename Head> struct length<typelist<Head, list_end>> : unsigned_<1> {}; template <typename> struct c_str; template <typename Head, typename Tail> struct c_str<typelist<Head, Tail>> { static void do_(char* p) { *p = Head::value; c_str<Tail>::do_(++p); } }; template <typename Head> struct c_str<typelist<Head, list_end>> { static void do_(char* p) { *p = Head::value; *++p = 0; } }; int main() { typedef typelist<char_<'H'>, typelist<char_<'e'>, typelist<char_<'l'>, typelist<char_<'l'>, typelist<char_<'o'>, typelist<char_<','>, typelist<char_<' '>, typelist<char_<'W'>, typelist<char_<'o'>, typelist<char_<'r'>, typelist<char_<'l'>, typelist<char_<'d'>, typelist<char_<'!'>, list_end>>>>>>>>>>>>> string; char str[length<string>::value + 1]; c_str<string>::do_(str); std::cout << str; }
-
@Kellerautomat
Das sowas geht ist schon klar
Ich meine ne statische, konstante Initialisierung.
Was wo kein Code draus wird, sondern was 1:1 direkt in der ".data" Section bzw. dem Äquivalent der jeweiligen Implementierung landet.
-
Kellerautomat schrieb:
Furble Wurble schrieb:
Ist std::identity() das neue void main()?
SCNR

?????
War beides nie Standard. Wird nur immer und immer wieder falsch gemacht, bzw. kopiert...
-
Dann eben etwas dreckiger:
template <typename> struct c_str; template <typename Head, typename Tail> struct c_str<typelist<Head, Tail>> { char const head = Head::value; c_str<Tail> const tail; }; template <typename Head> struct c_str<typelist<Head, list_end>> { char const head = Head::value; char const tail = 0; }; int main() { typedef typelist<char_<'H'>, typelist<char_<'e'>, typelist<char_<'l'>, typelist<char_<'l'>, typelist<char_<'o'>, typelist<char_<','>, typelist<char_<' '>, typelist<char_<'W'>, typelist<char_<'o'>, typelist<char_<'r'>, typelist<char_<'l'>, typelist<char_<'d'>, typelist<char_<'!'>, list_end>>>>>>>>>>>>> string; static c_str<string> const str; std::cout << reinterpret_cast<char const*>(&str); }Möglicherweise muss man dem Compiler auch noch sagen, dass er das struct packen soll, da bin ich gerade zu wenig mit dem Standard vertraut. Ideone kann leider keine Class-Member intialization, daher kann ich das leider nicht testen.
