NEW: Спасибо всем, кто помог мне с этим!Ответ помечен ниже, и я расширил ответ с функционирующей версией в своем вопросе ниже (qv):
Я, кажется, сталкиваюсь с этой ситуацией много (при обновлении нашегобиблиотека утилит строки):
Мне нужен способ иметь шаблон, который работает как для char, так и для wchar_t, который использует различные строковые литералы.В настоящее время я нахожу это сложным, потому что я не знаю, как во время компиляции изменить строковые литералы на узкие или широкие символы.
Для рассмотрения возьмем следующую функцию на основе TCHAR:
// 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);
}
Я хочу вместо этого создать шаблон:
// 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);
}
Сразу же возникла проблема с двумя строковыми литералами ('"' и"% c% s% c ").
Если приведенное выше вызывается для CSTRING_T = CStringA, CHAR_T = char, то с вышеуказанными литералами все в порядке. Но если оно вызывается для CStringW и wchar_t, то мне действительно нужны (L '"' и L"%c% c% c ").
Поэтому мне нужен какой-то способ сделать что-то вроде:
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);
}
И вот где я потерян: что в мире я могу сделать, чтобы сделать Literal(строка-или-символ-литерал), которая фактически приводит к L "строка" или "строка" в зависимости от CHAR_T?
Редактировать: Есть более ста функций, многие из которых более сложные с большим количеством строковых литераловв них это должно быть доступно как для узких, так и для широких струн.Если не считать копирование каждой такой функции, а затем редактирование каждой из них, чтобы она была либо широкой, либо узкой, безусловно, существует метод, который позволил бы получить одно определение, которое варьируется в зависимости от CHAR_T?
Я даю ответгибридный макрос + шаблон, предоставленный Марком Рэнсомом, но я хотел включить более полное решение (для всех, кому не все равно), поэтому вот оно:
// 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
Кроме того, я создал несколько помощников, чтобы писатьшаблоны, которые использовали эту концепцию в сочетании с CStringT <>, немного легче / приятнее для чтения и понимания:
// 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
С учетом вышеизложенного можно писать шаблоны, которые генерируют правильное разнообразие CString на основе CStringT <> или аргументы char / wchar_t.Например:
// 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;
}