新消息:感谢所有帮助我的人!下面标有答案,并且我在问题下方(请参见)扩展了答案的一个可行版本:
我似乎经常遇到这种情况(在更新我们的字符串工具库时):
我需要一种适用于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"string"或"string",具体取决于CHAR_T?
编辑:有100多个函数,其中许多更复杂,其中有更多的字符串文字需要同时适用于窄字符串和宽字符串。除了复制每个这样的函数,然后编辑每个函数以使其成为宽字符串或窄字符串之外,肯定有一种技术可以允许一个定义根据CHAR_T变化而不同吧?
我将回答Mark Ransom提供的混合宏+模板的答案,但我想包括一个更完整的解决方案(对于任何在意的人),因此在这里:
// 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 (https://dev59.com/ulLTa4cB1Zd3GeqPXiA1)
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
通过上述方法,可以编写模板以根据CStringT<>或char/wchar_t参数生成正确的CString变体。例如:
// 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;
}