NEU: Vielen Dank an alle, die mir dabei geholfen haben! Die Antwort ist unten markiert, und ich habe mit einer funktionierenden Version in meiner Frage auf der Antwort erweitert, unter (siehe dort):Vorlagen und String-Literale und UNICODE
Ich scheine viel in diese Situation zu laufen (während unseres String-Dienstprogramme Aktualisierung Bibliothek):
Ich brauche eine Möglichkeit, eine Vorlage, die für beide char und wchar_t, die verschiedene String-Literale verwendet funktioniert. Momentan finde ich das herausfordernd, weil ich nicht weiß, wie ich eine Kompilierzeit haben kann, um String-Literale als schmale oder breite Zeichen zu ändern.
Zur Erörterung, nehmen Sie die folgende TCHAR basierte Funktion:
// quote the given string in-place using the given quote character
inline void MakeQuoted(CString & str, TCHAR chQuote = _T('"'))
{
if (str.IsEmpty() || str[0] != chQuote)
str.Format(_T("%c%s%c"), chQuote, str, chQuote);
}
ich möchte es als Templat statt:
// quote the given string in-place using the given quote character
template <typename CSTRING_T, typename CHAR_T>
inline void MakeQuoted(CSTRING_T & str, CHAR_T chQuote = '"')
{
if (str.IsEmpty() || str[0] != chQuote)
str.Format("%c%s%c", chQuote, str, chQuote);
}
Ab sofort haben wir ein Problem mit den beiden Zeichenketten (" ', und "% c% s% c").
Wenn das obige für CSTRING_T = CStringA, CHAR_T = char aufgerufen wird, dann sind die obigen Literale in Ordnung. Wenn es für CStringW und wchar_t aufgerufen wird, dann reall y brauchen (L '"' und L"% c% c% c ").
Also muss ich einen Weg, etwas zu tun wie:
template <typename CSTRING_T, typename CHAR_T>
inline void MakeQuoted(CSTRING_T & str, CHAR_T chQuote = Literal<CHAR_T>('"'))
{
if (str.IsEmpty() || str[0] != chQuote)
str.Format(Literal<CHAR_T>("%c%s%c"), chQuote, str, chQuote);
}
Und das ist, wo ich bin verloren: Was in der Welt kann ich Wörtliche tun, um (String-oder-Zeichen-Literal), die tatsächlich Ergebnisse in L "string" oder "string" abhängig von CHAR_T?
Edit: Es gibt über hundert Funktionen, viele von ihnen komplexer mit mehr String-Literalen in ihnen, die für schmale und breite Strings verfügbar sein müssen. Kurz vor dem Kopieren jeder dieser Funktionen und dann jeder Bearbeitung entweder breit oder schmal, sicherlich gibt es eine Technik, die eine einzige Definition erlauben würde, die sich nach CHAR_T unterscheidet?
Ich gebe die Antwort auf den Hybrid-Makro + Vorlage, dass Mark Ransom geliefert, aber ich wollte eine vollständigere Lösung (für alle, die gepflegt) aufzunehmen, so ist es hier:
// we supply a few helper constructs to make templates easier to write
// this is sort of the dark underbelly of template writing
// to help make the c++ compiler slightly less obnoxious
// generates the narrow or wide character literal depending on T
// usage: LITERAL(charT, "literal text") or LITERAL(charT, 'c')
#define LITERAL(T,x) template_details::literal_traits<typename T>::choose(x, L##x)
namespace template_details {
// Literal Traits uses template specialization to achieve templated narrow or wide character literals for templates
// the idea came from me (Steven S. Wolf), and the implementation from Mark Ransom on stackoverflow (http://stackoverflow.com/questions/4261673/templates-and-string-literals-and-unicode)
template<typename T>
struct literal_traits
{
typedef char char_type;
static const char * choose(const char * narrow, const wchar_t * wide) { return narrow; }
static char choose(const char narrow, const wchar_t wide) { return narrow; }
};
template<>
struct literal_traits<wchar_t>
{
typedef wchar_t char_type;
static const wchar_t * choose(const char * narrow, const wchar_t * wide) { return wide; }
static wchar_t choose(const char narrow, const wchar_t wide) { return wide; }
};
} // template_details
Darüber hinaus habe ich einige Helfer schreiben Vorlagen zu machen, die dieses Konzept in Verbindung mit CStringT verwendet <> ein bisschen leichter/schöner & comprehend zu lesen:
// generates the correct CString type based on char_T
template <typename charT>
struct cstring_type
{
// typedef CStringT< charT, ATL::StrTraitATL< charT, ATL::ChTraitsCRT<charT> > > type;
// generate a compile time error if we're invoked on a charT that doesn't make sense
};
template <>
struct cstring_type<char>
{
typedef CStringA type;
};
template <>
struct cstring_type<wchar_t>
{
typedef CStringW type;
};
#define CSTRINGTYPE(T) typename cstring_type<T>::type
// returns an instance of a CStringA or CStringW based on the given char_T
template <typename charT>
inline CSTRINGTYPE(charT) make_cstring(const charT * psz)
{
return psz;
}
// generates the character type of a given CStringT<>
#define CSTRINGCHAR(T) typename T::XCHAR
Mit dem oben genannten ist es möglich, Vorlagen zu schreiben, die die richtige CString-Varietät basierend auf CStringT <> oder char/wchar_t-Argumenten generieren. Zum Beispiel:
// quote the given string in-place using the given quote character
template <typename cstringT>
inline void MakeQuoted(cstringT & str, CSTRINGCHAR(cstringT) chQuote = LITERAL(CSTRINGCHAR(cstringT), '"'))
{
if (str.IsEmpty() || str[0] != chQuote)
str.Format(LITERAL(cstringT::XCHAR, "%c%s%c"), chQuote, str, chQuote);
}
// return a quoted version of the given string
template <typename cstringT>
inline cstringT GetQuoted(cstringT str, CSTRINGCHAR(cstringT) chQuote = LITERAL(CSTRINGCHAR(cstringT), '"'))
{
MakeQuoted(str, chQuote);
return str;
}
Ich bin mir bewusst, dass ich Funktion Überladung verwenden kann, um zwei Definitionen für MakeQuoted zu generieren, anstatt eine einzige Vorlage zu verwenden, an welcher Stelle ich keine Sorgen über die Literale machen muss (siehe unten für @In Silicos Antwort). Das scheint jedoch albern zu sein, da ich den ganzen Code wortwörtlich wiederhole, nur um zwei verschiedene Sätze von Literalen zu liefern. Sicherlich gibt es eine Möglichkeit, Metaprogrammierung zu verwenden, um das richtige Literal (das typabhängige Literal) im laufenden Betrieb zu erzeugen. – Mordachai
@Mordachai: Keine Metaprogrammierung verwenden. Wenn das so wäre, könnten wir auch die Saiten einschalten. Können Sie ein Beispiel für eine Syntax nennen, die Sie verwenden möchten, um diese Funktion * zu verwenden? –
Ich bin mir nicht sicher, dass dies der Fall ist. Vorlagen generieren Code, der basierend auf den Typparametern variiert, die der Vorlage bereitgestellt werden. Nach was ich hier suche, ist ein Literal, das mit dem Typ variiert, der ihm geliefert wird. Vielleicht Template-Spezialisierung ?! Ich möchte, dass der Compiler die automatische Typ-Promotion für String-Literale durchführt (man denke an ein skalares Argument, die Vorlage würde ohne Aufwand funktionieren, da ein skalares Literal automatisch zum richtigen Typ hochgestuft wird. Nicht so für String-Literale). :( – Mordachai