Templates + Stringliterale
-
Man kennt das, ein Template ist vom Zeichentyp abhängig. In der Definition mit Literalen zu arbeiten, macht sich dann nicht so schön. Ich habe ein wenig rumgebastelt:
Eine Templatevariante:
literal<char>("bla")::value literal<wchar_t>("bla")::valueLässt sich leicht handhaben, kostet aber für wchar_t zur Laufzeit.
Dann hatte ich noch nen Makro, was aber immer eine Singlebyte und Multibyte Variante anlegt.
Wie geht ihr damit um?
-
bunga bunga schrieb:
Wie geht ihr damit um?
Wofür genau brauchst du sowas?
-
dot schrieb:
bunga bunga schrieb:
Wie geht ihr damit um?
Wofür genau brauchst du sowas?
Eigentlich nur aus Bequemlichkeit, weil ich nicht spezialisieren möchte. Die Implementation ist identisch, außer das die Literale angepasst werden müssen.
-
Ich kann mir trotzdem einfach nicht vorstellen, wofür man sowas brauchen sollte. Kannst du mir ein Anwendungsbeispiel geben?
-
pumuckl schrieb:
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

-
Wäre doch eigentlich überall ganz praktisch, wo es um Ein/Ausgabe geht.
Beispielsweise wenn der Ausgabeoperator überladen werden soll:
template <typename charT> std::basic_ostream<charT>& operator <<(std::basic_ostream<charT> s, const Foo& f) { s << literal_cast<charT>("bar() = ") << f.bar() << literal_cast<charT>("baz() = ") << f.baz(); }Bei der Instanziierung werden dann einfach die richtigen Adressen eingesetz und fertig.
-
Wenn du dich damit abfinden kannst
'b','a','r','(',')',' ','=',' 'zu schreiben gibt es einige schöne Lösungen. Ansonsten eher nicht.
Das String-Handling zur Compile-Zeit finde ich echt schwach gelöst von C++11.
@Nathan: Inwiefern kostet das nicht zur Laufzeit?
-
Danek schonmal, an string hatte ich gar nicht gedacht.
Wie kann das funktionieren?
auto tag = convertLiteral<E, Traits>("Element");tag müsste doch eigenlich leer sein?!
-
Das ist C++11, google mal auto.
Und die Laufzeitkosten sind dank inline und move quasi null.
-
@Nathan: Mit move hat das rein gar nichts zu tun, der Punkt ist halt, dass bei dir das String-Literal als char[] im Datensegment liegt und dann zur Laufzeit darüberiteriert werden muss um jedes Zeichen in wchar_t zu konvertieren.
Ich habe hier eine Version, bei der ein wchar_t[] im Datensegment abgelegt wird:
// <kopiert author="camper"> template <typename T> struct identity_ { using type = T; }; template <int... i> struct index_list : identity_<index_list<i...>> {}; template <int N, typename = index_list<>> struct make_index_list_; template <int N, typename T = index_list<>> using make_index_list = typename make_index_list_<N, T>::type; template <int N, int... i> struct make_index_list_<N, index_list<i...>> : make_index_list<N-1, index_list<0, 1+i...>> {}; template <int... i> struct make_index_list_<0, index_list<i...>> : index_list<i...> {}; // </kopiert> template <typename C, unsigned N> struct string_lit { C data[N]; }; template <class C, unsigned N, int... I> constexpr string_lit<C, N> convert_literal_(char const(& lit)[N], index_list<I...>) { return {{ static_cast<C>(lit[I])... }}; } template <class C, unsigned N = 0> constexpr string_lit<C, N> convert_literal(char const(& lit)[N]) { return convert_literal_<C, N>(lit, make_index_list<N>{}); } void gtmarg() { constexpr auto lit = convert_literal<wchar_t>("hello world, this is a very very very long string and it has to be stored in a very very constant array"); printme(lit.data); }
-
Nathan schrieb:
Das ist C++11, google mal auto.
Auto hat damit gar nichts zu tun, ich war überrascht, dass man die Größe des Arrays einfach über das Template-Pattern abgreifen kann und sie nicht explizit angeben muss.
@gtmarg + camper
Danke, genau das was ich suche. Leider noch zuviel C++11 für den VC11. Ich habs vorübergehend erstmal so gelöst:template <typename CharT> struct string_literal; template <> struct string_literal<char> { string_literal(const char* lit) : data(lit) {} const char* data; inline const char* c_str() {return data;} }; template <> struct string_literal<wchar_t> { template <std::size_t SizeV> string_literal(char const(& lit)[SizeV]) : data(lit, lit + SizeV - 1) {} std::wstring data; inline const wchar_t* c_str() {return data.c_str();} }; template <typename CharT> inline std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& s, const string_literal<CharT>& l) { return s << l.data; }Btw, macht es sind mit
#if __cplusplus >= 201103Lden Standard zu prüfen?
MfG