Rot13 Template?



  • Geht nicht. Du kannst String-Literale nicht zur Compilezeit ändern. Was gehen würde, ist, dass Du das Literal aus einzelnen chars zusammensetzt.
    So in der Art: rot13<'d', 'e', 'r', ' ', 'T', 'e', 'x', 't'>::literal . Das ist aber natürlich nicht schön.
    Wie wäre es, wenn Du ein kleines Programm schreibst, dass alle Deine Quellen durchgeht, und Klartext-Strings mit verschwurbelten Strings ersetzt? So schwer ist das nicht.



  • Ah hm ja, bleibt das Problem, dass es nicht geht.



  • cooky451 schrieb:

    Ah hm ja, bleibt das Problem, dass es nicht geht.

    Wieso sollte das nicht gehen? Vermutlich würde man das zum Beispiel mit einem etwas angepassten boost.assign hinbekommen. Insbesondere aber mit c++11 sollte das nicht so schwer sein.


  • Mod

    Tachyon schrieb:

    cooky451 schrieb:

    Ah hm ja, bleibt das Problem, dass es nicht geht.

    Wieso sollte das nicht gehen? Vermutlich würde man das zum Beispiel mit einem etwas angepassten boost.assign hinbekommen. Insbesondere aber mit c++11 sollte das nicht so schwer sein.

    assign wird zur Laufzeit ausgeführt. Du kannst Zeichenkettenliterale tatsächlich nicht zur compilezeit verändern, weder mit Templates, noch mit Makros (versuch es mal, damit du verstehst, warum es nicht geht!). Das was dem am nächsten kommt, 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. Hier bietet sich irgendeine Art externes Programm an, welches man noch vor dem Präprozessor auf den Quellcode loslässt.



  • SeppJ schrieb:

    Hier bietet sich irgendeine Art externes Programm an, welches man noch vor dem Präprozessor auf den Quellcode loslässt.

    Was ich ja auch geschrieben habe. 😉



  • 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