template funktion
-
Hallo Werner, danke für die Antwort.
Ich habe deinen zweiten Vorschlag verwendet,
und wenn ich die Funktion nur mit einem Char-Array
aufrufe funktioniert es taldellos. Rufe
ich die Funktion hingegen mit einem wchar_t-Array auf,
bekomme ich 2 Fehler:In Zeile 6:
Umwandlung von »const char [8]« in nicht-skalaren Typen »const std::basic_string<wchar_t>« angefordertund in Zeile 8:
keine passende Funktion für Aufruf von »std::basic_string<wchar_t>::replace(size_t&, std::basic_string<wchar_t>::size_type, const char [8])«Die Zeichenketten "Element" und "Tnemele" liegen als Char-Arrays vor und können nicht direckt in einen wstring umgewandelt werden.

-
Die Literale müssen natürlich auch wchar_t sein!
-
leider ist es so einfach nicht, dann funktioniert die Funktion zwar mit wchar_t-Arrays, aber nicht mehr mit char-Arrays. Die Literale müssen auch generisch sein. Das ist wirklich ganz schön knifflig.!
-
http://www.c-plusplus.net/forum/39492-full
Casten ist das Stichwort.
-
hast Du die Funktionen von Werner überhaupt im Ansatz verstanden? Wie man casted weiß ich, aber das hilft hier nicht. Ich brauche einen generischen Ansatz keinen statischen.
-
Oder beide Varianten von Werner zusammen, um unnötige Temporaries zu vermeiden (C++11 move-Ctors). Für die Literale muss man dann noch einen kleinen Umweg gehen:
std::pair<char const*, char const*> getReplacement(char*) { return std::make_pair("Element", "Tnemele"); } std::pair<wchar_t const*, wchar_t const*> getReplacement(wchar_t*) { return std::make_pair(L"Element", L"Tnemele"); } template< typename E, typename Traits > std::basic_string< E, Traits > replaceElements( std::basic_string< E, Traits > str ) { typedef std::basic_string< E, Traits > string_t; auto replacement = getReplacement((E*)0); string_t tag(replacement.first); auto pos = str.find(tag); if (pos != string_t::npos) str.replace(pos, tag.length(), replacement.second); return str; } template <typename E> auto replaceElements(E const* ptr) -> std::basic_string<E> { return replaceElements(std::basic_string<E>(ptr)); }
-
@Soahc:
Was sprichst dagegen nach basic_string<E, Traits> zu casten?
Pumuckls Idee wäre mein zweiter Vorschlag gewesen.Edit: Zum casten kannst du dank den char_traits auf den zugrundeliegenden Zeichentyp zugreifen. Das ist dann ein komplett generischer Ansatz.
-
Nathan schrieb:
@Soahc:
Was sprichst dagegen nach basic_string<E, Traits> zu casten?
Pumuckls Idee wäre mein zweiter Vorschlag gewesen.Edit: Zum casten kannst du dank den char_traits auf den zugrundeliegenden Zeichentyp zugreifen. Das ist dann ein komplett generischer Ansatz.
Wie sollen die beiden Vorschläge funktionieren? Bitte gib mal Beispiele für den Cast auf basic_string<E, T> und den ominösen "komplett generischen Ansatz". Du kannst nicht ohne Spezialbehandlung mit einem Literal beide Stringtypen abfackeln.
Aber von alledem mal ganz abgesehen: lass den ganzen Quatsch, lass wchar_t komplett weg, das ist eh keine gute Idee.
-
Es geht sogar viel einfach wie ich gerade feststellen konnte.
string literal = "Das Literal, immer vom Typ string."; funktionDieLiteralBraucht(basic_string<E, Traits>(literal.begin(), literal.end()));Klappt bei mir (gcc und C++11) wunderbar.
-
danke pumuckl! gut ich musste erstmal ein wenig mit dem compiler kämpfen, dass er c++11 verwendet. Aber jetzt funktioniert es. Vielen Dank!
-
Nathan schrieb:
Es geht sogar viel einfach wie ich gerade feststellen konnte.
string literal = "Das Literal, immer vom Typ string."; funktionDieLiteralBraucht(basic_string<E, Traits>(literal.begin(), literal.end()));Klappt bei mir (gcc und C++11) wunderbar.
Gute Idee, danke

template <class E, class T = std::char_traits<E>, unsigned N = 0> std::basic_string<E, T> convertLiteral(char const(& lit)[N]) { return std::basic_string<E, T>(lit, lit+N); } template< typename E, typename Traits > std::basic_string< E, Traits > replaceElements( std::basic_string< E, Traits > str ) { auto tag = convertLiteral<E, Traits>("Element"); auto pos = str.find(tag); if (pos != decltype(str)::npos) str.replace(pos, tag.length(), convertLiteral<E, Traits>("Tnemele")); return str; } template <typename E> auto replaceElements(E const* ptr) -> std::basic_string<E> { return replaceElements(std::basic_string<E>(ptr)); }Trotzdem kein wchar_t bitte

-
Die letzte Variante funktioniert bei mir leider nicht. Ich kann zwar kompilieren, aber die Elemente werden nicht getauscht.
-
@pumuckl:
Gern geschehen.
War für mich auch neu.
-
Soahc schrieb:
Die letzte Variante funktioniert bei mir leider nicht. Ich kann zwar kompilieren, aber die Elemente werden nicht getauscht.
Mal mit dem Debugger reingeschaut?
/edit: ich kanns nachstellen, dass das nicht funktioniert: http://ideone.com/kOLmiU
-
Es liegt nicht an der Literal-Umwandlung, bei std::string klappt es auch nicht...
-
Ich wollte gern noch eine Zusatzfunktion schreiben:
template<typename E> E const* replaceElements(E const* ptr){ return replaceElements(ptr).c_str(); }mit der ich den ursprünglich übergebenen Zeiger umbiegen kann.:
const char *str= "Teste mit Element"; const wchar_t *wstr= L"Teste ebenfalls mit Element"; str= replacePointer(str); wstr= replacePointer(wstr);Es wird kompiliert, aber das verhalten ist unvorhersehbar. Rufe ich die Funktion nur einmal auf, dann funktioniert es wie gewünscht, rufe ich sie mehrmals hintereinander auf, dann kommt nur murks dabei raus. Ich vermute, der vom basic_string<E> angeforderte Speicher wird nach dem aufruf von replacePointer wieder freigegeben?! Stimmt das? Und gibt es eine Möglichkeit eine solche Funktion zu schreiben?
-
Soahc schrieb:
Und gibt es eine Möglichkeit eine solche Funktion zu schreiben?
Nicht so wirklich. Das Problem was du hast ist, dass der innere Aufruf von replaceElements einen temporären string erzeugt. Auf dem rufst du c_str auf, aber direkt danach wird er zerstört, du hast also einen ungültigen Pointer. Dass das mal "funktioniert" und mal nicht, ist typisch für undefiniertes Verhalten.
-
auch wenn sich das ein bisschen nach Holzhammer-Methode anhört... könnte ich nicht in replacePointer per new-operator ein char bzw. E-array erzeugen, dann die werte des temporären c-strings dort per memcpy hinein kopieren und einen pointer darauf zurück geben?
-
wenn du an einer Stelle mit op new [] etwas anlegst, muß du es an anderer Stelle mit op delete [] wieder freigeben
-
Warum brauchst du überhaupt eine Funktion für Pointer/Char-Arrays?
Und ja, das wäre eine Methode, wenn auch eine schlechte...
Wenn dann einen unique_ptr-Array zurückgeben, das wird im Zweifelsfall automatisch gelöscht.