Code in C++?



  • Versuch Du mal ein Programm leicht von char auf wchar_t zu konvertieren ohne größere Probleme. 🙄

    gibt zwar das TEXT-Makro aber das gehört zu Windows, auch wenn ich ein eigenes Benutze wollte ichs nicht noch zusätzlich posten, deshalb template-Lösung, vorallem da ich #define net besonders mag 😉



  • Patrick @ Kumpels (sogar bei Kumpels schon im Forum) schrieb:

    Versuch Du mal ein Programm leicht von char auf wchar_t zu konvertieren ohne größere Probleme. 🙄

    Mein Ansatz wäre sowas:

    template<class T> MichaelE_HelpFunctions
    {
        basic_string<T> find_last_of(basic_string<T> in, basic_string<T> toFind)
        {
            return in.find_last_of(toFind);
        }
    
        basic_string<T> substr(basic_string<T> s,
                            basic_string<T>::size_type beg = s.begin(),
                            basic_string<T>::size_type end = basic_string<T>::npos)
        {
            return s.substr(beg, end);
        }
    }
    

    Wenn man eine Funktion nicht so verallgemeinern kann, muss man die einzelnen Templates spezialisieren.



  • Patrick @ Kumpels schrieb:

    template<typename T> const inline std::basic_string<T> removeDir (const std::basic_string<T>& value) 
    { throw "Datentyp wurde nicht implementiert!"; }
    
    template<char> const inline std::basic_string<char> removeDir (const std::basic_string<char>& value) 
    { return (value.substr(value.find_last_of("\\"))); }
    
    template<wchar_t> const inline std::basic_string<wchar_t> removeDir (const std::basic_string<wchar_t>& value) 
    { return (value.substr(value.find_last_of(L"\\"))); }
    

    Habs nur aus dem Kopf gemacht.

    man könnte doch stattdessen ne funktion schreiben, die char nach wchar_t konvertiert, oder? dann würde dieses wiederholte schreiben des codes unnötig

    //keine garantie, dass folgendes richtig/sinnvoll ist, ich arbeite net oft mit locales
    
    #include <iostream> //für die locales von cout
    
    template<class T,class U>
    std::basic_string<T> convert(const std::basic_string<U>& str){
        std::basic_string<T> output;
        output.reserve(str.size());
        std::use_facet<std::ctype<T> > (std::cout.getloc()).widen(str.begin(),str.end(), output);
        return output;
    }
    
    //wenn start und zieltyp gleich sind, ist keine konvertierung erforderlich
    template<class T>
    const std::basic_string<T>& convert(const std::basic_string<T>& str){
        return str;
    }
    
    template<class T> const inline std::basic_string<T> removeDir (const std::basic_string<T>& value) 
    { 
        return value.substr(value.find_last_of(convert<T>("\\"))); 
    }
    

    //edit wahrscheinlich gibts aber ne um einiges bessere funktion bei boost 🙄



  • @otze
    du gehst aber nur auf folgende ein und vergisst eines!
    OK: char -> char
    OK: char -> wchar_t
    OK: wchar_t -> wchar_t
    ??: wchar_t -> char



  • stimmt...widen geht ja nur in eine richtung 😕



  • Michael E. schrieb:

    string removeDir(string f)
    {
        return f.substr(f.find_last_of("\\"));
    }
    

    leider falsch. das original liefert einen pointer in den eingabestring zurück. das hier kopiert einen teilstring raus.



  • Falsch! beide richtungen gehen, sieht man ja auch an der WinAPI:

    inline std::wstring to_wstring(const std::string& s,const std::locale& loc = std::locale())
    {
      std::vector<wchar_t> ret(s.size(),0);
      const char* pCC = s.c_str();
      mbstate_t state;
      wchar_t* pW = &*ret.end();
      const char* pC = pCC+s.size();
      std::use_facet<std::codecvt<wchar_t,char,mbstate_t> >(loc).in(state,pCC,pCC+s.size(),pC,&*ret.begin(),&*ret.end(),pW);
      return std::wstring(&*ret.begin(),pW);
    }
    
    inline std::string to_string(const std::wstring& ws,const std::locale& loc = std::locale())
    {
      std::vector<char> ret(ws.size()*6,0);
      const wchar_t* pCW = ws.c_str();
      mbstate_t state;
      const wchar_t* pW = pCW+ws.size()*6;
      char* pC = &*ret.end();
      std::use_facet<std::codecvt<wchar_t,char,mbstate_t> >(loc).out(state,pCW,pCW+ws.size()*6,pW,&*ret.begin(),&*ret.end(),pC);
      return std::string(&*ret.begin(),pC);
    }
    

    Jetzt müsst ihr das nur noch in einen schonen cast basteln 🙂 habs mal versucht aber kenn mich mit templates leider 0 aus 😞



  • Warum * 6? lol



  • Compilezeitfehler sind besser als Laufzeitfehler, was in diesem Fall bedeutet:

    template<typename CharT> struct dir_delim { };
    template<> struct dir_delim<char> { static const char val = '/'; };
    template<> struct dir_delim<wchar_t> { static const char val = L'/'; };
    
    template<typename StringT> StringT get_filename(StringT const &path) {
      return path.substr(path.find_last_of(dir_delim<typename StringT::value_type>::val) + 1);
    }
    


  • Uh...in dir_delim<wchar_t> muss val natürlich auch ein wchar_t sein.



  • net schrieb:

    Michael E. schrieb:

    string removeDir(string f)
    {
        return f.substr(f.find_last_of("\\"));
    }
    

    leider falsch. das original liefert einen pointer in den eingabestring zurück. das hier kopiert einen teilstring raus.

    Dann halt so:

    void removeDir(string &f)
    {
        f.erase(f.find_last_of("\\"));    // Zweiter Parameter optional??
    }
    


  • Michael E. schrieb:

    net schrieb:

    Michael E. schrieb:

    string removeDir(string f)
    {
        return f.substr(f.find_last_of("\\"));
    }
    

    leider falsch. das original liefert einen pointer in den eingabestring zurück. das hier kopiert einen teilstring raus.

    Dann halt so:

    void removeDir(string &f)
    {
        f.erase(f.find_last_of("\\"));    // Zweiter Parameter optional??
    }
    

    auch nicht richtig. das verändert das original. gar nicht so einfach, ne?



  • |even| schrieb:

    Falsch! beide richtungen gehen, sieht man ja auch an der

    die benutzen aber auch 2 verschiedene funktionen zum konvertieren, und das ist das problem!

    widen kann halt nur kleiner typen zu größeren konvertieren(char->wchar_t als beispiel), für den umgekehrten weg braucht man aber narrow(wchar_t->char).

    (aber der von mir gepostete code reicht für den hier geposteten fall vollauf, das umwandeln von wchar_t nach char war halt net verlangt^^)



  • net schrieb:

    Michael E. schrieb:

    net schrieb:

    Michael E. schrieb:

    string removeDir(string f)
    {
        return f.substr(f.find_last_of("\\"));
    }
    

    leider falsch. das original liefert einen pointer in den eingabestring zurück. das hier kopiert einen teilstring raus.

    Dann halt so:

    void removeDir(string &f)
    {
        f.erase(f.find_last_of("\\"));    // Zweiter Parameter optional??
    }
    

    auch nicht richtig. das verändert das original. gar nicht so einfach, ne?

    Mir ist schon klar, dass das das Original verändert. Aber gucks dir doch mal an:

    Man braucht einen Teil des Strings. Es ist eigentlich total unwichtig, wo der steht. Also hab ich ne Kopie zurückgeliefert. Weil du aber keine Kopie haben willst, hab das Original verändert. Was passt dirr denn dadran nicht? Dass es nicht 100% mit dem C-Code übereinstimmt? Wenn ja, dann lass es doch gleich stehen. Praktisch gesehen ist da kein Unterschied.

    Und komm bitte nicht mit sowas:

    string foo = "j\djlfj\u";
    string bar = removeDir(foo);
    foo += "z";    // bar hat jetzt immer noch denselben Wert
    

    Wer sowas schreibt, hat nen Fehler in der Denkweise.



  • Michael E. schrieb:

    Es ist eigentlich total unwichtig, wo der steht. Also hab ich ne Kopie zurückgeliefert. Weil du aber keine Kopie haben willst, hab das Original verändert. Was passt dirr denn dadran nicht? Dass es nicht 100% mit dem C-Code übereinstimmt? Wenn ja, dann lass es doch gleich stehen. Praktisch gesehen ist da kein Unterschied.

    der originalcode liefert einen pointer hinter das letzte \ zurück. und genau sowas erwartet der aufrufer, keine kopie, keine manipulation an den daten (was ist wenn die read-only sind?) das macht keiner deiner codes. du hast etwas völlig anderes programmiert :p



  • net schrieb:

    der originalcode liefert einen pointer hinter das letzte \ zurück. und genau sowas erwartet der aufrufer, keine kopie, keine manipulation an den daten (was ist wenn die read-only sind?)

    Falsch.

    Wenn du die Frage genau lesen würdest: es geht darum, wie man das in C++ macht.

    Beachte: C und C++ sind verschiedene Sprachen. Eine Lösung in C++ würde somit idR anders aussehen als in C. Folglich sind die Codes nicht falsch, sondern allesamt richtig, weil sie den Anforderungen entsprechen.

    Ich habe es woanders schonmal gesagt: bitte troll nicht dauernd rum.
    und @Michael E.: lass dich nicht aufziehen.



  • Shade Of Mine schrieb:

    Wenn du die Frage genau lesen würdest: es geht darum, wie man das in C++ macht.

    das steht da. irgendwelche missverständnisse? ich glaube nicht....

    Shade Of Mine schrieb:

    Beachte: C und C++ sind verschiedene Sprachen. Eine Lösung in C++ würde somit idR anders aussehen als in C.

    da bin ich genau deiner meinung.

    Shade Of Mine schrieb:

    Folglich sind die Codes nicht falsch, sondern allesamt richtig, weil sie den Anforderungen entsprechen.

    nein. die anforderung ist in etwa "schreibe eine funktion in c++, welche einen char* (c-string) bekommt und einen zeiger hinter das letzte vorkommen von \ liefert"

    edit: damit ihr nicht denkt ich motze nur rum...

    char* removeDir (char* pcFilename)
    {
      return 1 + pcFilename + string(pcFilename).find_last_of("\\");        
    }
    


  • net schrieb:

    nein. die anforderung ist in etwa "schreibe eine funktion in c++, welche einen char* (c-string) bekommt und einen zeiger hinter das letzte vorkommen von \ liefert"

    Nö, z.B. steht nirgendwo, dass man C-Strings benutzen sollte.
    Nach deiner Auffassung könnte man auch einen Iterator zurückliefern.

    Shade hat Recht. Ich klink mich aus.



  • Michael E. schrieb:

    Nö, z.B. steht nirgendwo, dass man C-Strings benutzen sollte.

    sollte man auch nicht, denn der op fragte nach einer c++ lösung. allerdings finde ich, dass man input und output der funktion schon dabei beachten sollte.

    Michael E. schrieb:

    Shade hat Recht.

    wenn ich schreiben würde 'heilig abend ist am 24. dezember' und du würdest schreiben 'es ist am 1. januar' würde er dir auch recht geben 😉



  • wie sähe dieser Code in C++ aus?

    Ganz einfach: in C++ sähe sie etwa so aus

    string removeDir(string const& f)
    {
        return f.substr(f.find_last_of("\\"));
    }
    

    ist doch vollkommen richtig.

    Wenn jemand fragt: wie sähe die Funktion in Java aus, würde wohl niemand sagen: Das geht nicht, weil Java keine Zeiger kennt. Sondern einfach eine Java Lösung posten die String verwendet.

    Man kann die Funktion _auch_ anders schreiben. Aber dieser Code ist eine legitime C++ Version der C Version. Sie sind nicht identisch, denn identisch das ist nicht möglich (mit der Ausnahme von kleinigkeiten wie zB laufende Zeiger zu verwenden, oder keine ungarische notation oder size_t statt int, etc. - was man in C aber sowieso auch machen könnte).

    Wenn du es also so siehst, dann ist die einzige Antwort die man gelten lassen kann:
    C++ kann das leider nicht.

    char* removeDir (char* pcFilename) 
    { 
      return 1 + pcFilename + string(pcFilename).find_last_of("\\");         
    }
    

    ist übrigens eine verdammt schlechte lösung. sowas würde man nie schreiben.


Anmelden zum Antworten