Rot13 Template?



  • Sepp schrieb:

    wäre wohl eine Krücke nach der Art

    rot13<'H', 'a', 'l', 'l', 'o'>()::value;
    

    Das ginge, ist aber sicher nicht nach der Vorstellung des Threaderstellers.

    #include <iostream>
    
    template<char c>
    char constexpr rot13C()
    {
           return (c + 13 > (c >= 'A' && c <= 'Z' ? 'Z' : 'z'))? c - 13 : c + 13;     //Edit²: Lol! Jetzt gehen aber auch Kleinbuchstaben.
    }
    
    template<char...c>
    struct rot13
    {
            static char constexpr value[] = { rot13C<c>()..., '\0' };
    };
    
    template<char...c>
    char constexpr rot13<c...>::value[];
    
    int main()
    {
            std::cout << rot13<'B', 'l', 'a'>::value << '\n';
    }
    

    Das wäre mein Vorschlag, aber der ist IMO nicht besonders hübsch... 😞



  • WAs auch noch lustig wäre: User-Defined Literals mit Variadic Templates. Aber da hab ich schon keine Lust mehr drauf.

    Edit: Nein, gehen kann das gar nicht.



  • Eine Möglichkeit, das ganze etwas schöner zu machen, sind zusammengesetzt int-Literale aus chars.

    template <int...> struct string { ... };
    typedef string<'Hell', 'o Wo', 'rld!'> s;
    ...
    

    Ist ein bisschen besser lesbarer.

    @Sone: Du bist ein Idiot. GTFO.


  • Mod

    #define ROT13_1(str,x)  str[pos<sizeof str?pos:sizeof str-1]
    #define ROT13_2(str,x)  ROT13_1(str,x), ROT13_1(str,x+1)
    #define ROT13_4(str,x)  ROT13_2(str,x), ROT13_2(str,x+2)
    #define ROT13_8(str,x)  ROT13_4(str,x), ROT13_4(str,x+4)
    #define ROT13_16(str,x) ROT13_8(str,x), ROT13_8(str,x+8)
    #define ROT13_32(str,x) ROT13_16(str,x), ROT13_16(str,x+16)
    #define ROT13_64(str,x) ROT13_32(str,x), ROT13_32(str,x+32)
    #define ROT13(str)    rot13<ROT13_64(str, 0)>::value;
    

    Den String auf die richtige Läge zurückzukürzen, ist eine kleine Übungsaufgabe.
    Mit boost-PP wird es noch etwas einfacher.



  • Nachdem ich nun ein halbes Dutzend Bugs in meinem Code behoben durfte (dadurch rechtfertigt sich Kellerautomats Aussage natürlich 😃 ), funktioniert das:

    #include <iostream>
    
    template<char c>
    char constexpr rot13C()
    {
            return (c + 13 > (c >= 'A' && c <= 'Z' ? 'Z' : 'z'))? c - 13 : c + 13;
    }
    template<>
    char constexpr rot13C<'\0'>()
    {
            return '\0';
    }
    
    template<char...c>
    struct rot13
    {
            static char constexpr value[] = { rot13C<c>()..., '\0' };
    };
    
    template<char...c>
    char constexpr rot13<c...>::value[];
    
    #define ROT13_1(str,pos)  str [ pos < sizeof str ? pos : sizeof str - 1 ]
    #define ROT13_2(str,x)  ROT13_1(str,x), ROT13_1(str,x + 1)
    #define ROT13_4(str,x)  ROT13_2(str,x), ROT13_2(str,x + 2)
    #define ROT13_8(str,x)  ROT13_4(str,x), ROT13_4(str,x + 4)
    #define ROT13_16(str,x) ROT13_8(str,x), ROT13_8(str,x + 8)
    #define ROT13_32(str,x) ROT13_16(str,x), ROT13_16(str,x + 16)
    #define ROT13_64(str,x) ROT13_32(str,x), ROT13_32(str,x + 32)
    #define ROT13(str)    rot13< ROT13_64( (str), 0) >::value //Hier müssen btw besser Klammern um str
    
    int main()
    {
            std::cout << ROT13("Bla") << '\n'; //Die ROT13-Version des Textes
            std::cout << ROT13( ROT13("Bla") ) << '\n'; // Verschlüsselt und zurück
    }
    

    Funktioniert mit meinem GCC 4.8, auf Ideone gibt es einen Haufen Fehlermeldungen. Was solls.


  • Mod

    Sone schrieb:

    std::cout << ROT13( ROT13("Bla") ) << '\n'; // Verschlüsselt und zurück
    

    Und in diesem Augenblick steht "Bla" wieder in der Executable.



  • SeppJ schrieb:

    Sone schrieb:

    std::cout << ROT13( ROT13("Bla") ) << '\n'; // Verschlüsselt und zurück
    

    Und in diesem Augenblick steht "Bla" wieder in der Executable.

    War nur ein Beispiel! 😃

    Am Ende sieht AFAIK die main-Funktion (vereinfacht) ja so aus:

    int main()
    {
            std::string str = ROT13("Bla");
    
            std::cout << transform(str) << '\n';//Hier zur Laufzeit zurückverwandelt
    }
    


  • Die ständige Rücktransformation sollte man sich eigentlich sparen können:

    std::string s = rot13(ROT13("Hallo Welt")); // rot13 normale Funktion
    

    Dabei eventuell dafür sorgen, dass rot13 nicht rausoptimiert und dann wirklich erst zur Laufzeit einmalig ausgeführt wird. Könnte man eventuell auch gleich mit ins Makro packen.


  • Mod

    Also am Besten so, dass ROT13 ein Objekt darstellt, mit einem Konvertierungsoperator für string.



  • camper schrieb:

    Also am Besten so, dass ROT13 ein Objekt darstellt, mit einem Konvertierungsoperator für string.

    So?

    Edit: Verbessert.

    #include <iostream>
    #include <string>
    #include <mutex>
    
    template<typename T>
    struct identity final  {typedef T type;};
    
    template<char c>
    bool constexpr isalpha()
    {
            return        c >= 'A'
                       && c <= 'Z'
                    ||    c >= 'a'
                       && c <= 'z';
    }
    
    #define ret_expr(func) ( func )? \
                              (c + 13 > ( c <= 'Z' ? 'Z' : 'z' ) )? c - 13 : c + 13  \
                              : \
                              c//... oder einfach den Buchstaben zurückgeben
    
    template<char c>
    char constexpr rot13C() //Template Version (zur Compilezeit)
    {
            return ret_expr(isalpha<c>());
    }
    
    char rot13C(char const c) //Normale Funktion (Laufzeit)
    {
            return ret_expr(std::isalpha(c));
    }
    
    std::string rot13str(std::string const& s)
    {
            std::string rval( s );
    
            for(auto &c : rval)
                    c = rot13C(c);
    
            return rval;
    }
    
    template<char...c>
    struct rot13
    {
            static char constexpr value[] = { rot13C<c>()..., '\0' };
    
            operator std::string()
            {
                    return rot13str( value );
            }
    
            operator typename identity<char const(&)[sizeof value]>::type () const //selbst gebastelt, sonst geht auch die boost::move_details Version
            {
                 static char arr[sizeof value]{};
                 static std::once_flag f;
                 std::call_once(f, memcpy, arr, rot13str(value).c_str(), sizeof(value));
                 return arr;
            }
    };
    
    template<char...c>
    char constexpr rot13<c...>::value[];
    
    #define ROT13_1(str,pos)  str [ pos < sizeof str ? pos : sizeof str - 1 ]
    #define ROT13_2(str,x)  ROT13_1(str,x), ROT13_1(str,x + 1)
    #define ROT13_4(str,x)  ROT13_2(str,x), ROT13_2(str,x + 2)
    #define ROT13_8(str,x)  ROT13_4(str,x), ROT13_4(str,x + 4)
    #define ROT13_16(str,x) ROT13_8(str,x), ROT13_8(str,x + 8)
    #define ROT13_32(str,x) ROT13_16(str,x), ROT13_16(str,x + 16)
    #define ROT13_64(str,x) ROT13_32(str,x), ROT13_32(str,x + 32)
    #define ROT13(str)    rot13< ROT13_64( (str), 0) >() //Hier wird ein temporäres rvalue instanziiert
    
    int main()
    {
            char const* s = ROT13("Hallo w"); // rot13 normale Funktion
            std::cout << s << '\n';
    }
    

    Klar, hier ist ROT13 selbst nicht ein Objekt, aber was ich meine dürfte klar sein.
    Dazu kann man noch ROT5 mit reinpacken.


  • Mod

    jetzt noch die überflüssigen '\0' Zeichen am Ende entfernen und eine Konvertierung nach const char(&)[N] statt const char* anbieten. Dann dürfte das sogar einigermaßen brauchbar sein.



  • Moinsen,

    Warum nicht einfach alle Zeichenketten in einem pre build event mit einen separaten Programm verschlüsseln und nur die dekodier Funktion einbauen?

    Grüße



  • camper schrieb:

    jetzt noch die überflüssigen '\0' Zeichen am Ende entfernen und eine Konvertierung nach const char(&)[N] statt const char* anbieten. Dann dürfte das sogar einigermaßen brauchbar sein.

    Mir fällt auf die Schnelle nur

    operator typename identity<char const(&)[sizeof(value)]>::type () const //selbst gebastelt, sonst geht auch die boost::move_details Version
    {
         static char arr[sizeof value]{};
         static std::once_flag f;
         std::call_once(f, memcpy, arr, value, sizeof(value));
         return arr;
    }
    

    ein ( std::identity wurde btw afair aus dem Standard gebannt).
    Die Template-Version (mit <size_t N> ) scheint irgendwie nicht zu klappen.

    Man kann natürlich auch gleich das interne Array zurückgeben.

    Was die überflüssigen Terminierungszeichen am Ende betrifft: Ich bin leider echt gar nicht vertraut mit Boost-Preprocessor (und will hier auch nur Standard einbeziehen), und wie es sonst gehen soll überlasse ich dem Meister.

    Edit: Hab jetzt obigen Code editiert.



  • *push*

    Camper, mach doch was! Also wie kann man das jetzt kuerzen? Mir faellt kein Spielchen mit dem PP ein.
    EDit: Ich hab es mit dem ternaeren Operator im Makro versucht, ala

    #define ROT13_64(str,x) ROT13_32(str,x), (sizeof str > x + 32 + 16)? ROT13_32(str,x + 32) : ROT13_16(str, x + 32)
    

    Aber der Compiler meldet, dass nach dem aufloesen der Makros Operanden des Komma-Operators einfach ignoriert werden...


Anmelden zum Antworten