【发布时间】:2011-05-14 18:49:00
【问题描述】:
新:感谢所有帮助我的人!答案标记在下面,我在下面(q.v.)的问题中使用功能版本扩展了答案:
我似乎经常遇到这种情况(在更新我们的字符串实用程序库时):
我需要一种方法来创建一个适用于 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'"', and 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);
}
这就是我迷失的地方:我该怎么做才能根据 CHAR_T 生成 L"string" 或 "string" 的 Literal(string-or-character-literal)?
编辑:有超过一百个函数,其中许多更复杂,其中包含更多字符串文字,需要同时适用于窄字符串和宽字符串。除了复制每个这样的函数,然后将每个函数编辑为宽或窄,肯定有一种技术可以允许单个定义随 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 (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
通过以上内容,可以编写基于 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;
}
【问题讨论】:
-
我知道我可以使用函数重载为 MakeQuoted 生成两个定义,而不是使用单个模板,此时我不需要担心文字(请参阅下面的 @In硅的回答)。但是,考虑到我逐字重复所有代码只是为了提供两组不同的文字,这似乎很愚蠢。肯定有某种方法可以使用元编程即时生成正确的文字(依赖于类型的文字)?
-
@Mordachai:不使用元编程。如果有的话,我们也可以打开字符串。你能举一个你想用来使用这个函数的语法的例子吗?
-
我不确定是不是这样。模板生成的代码根据提供给模板的类型参数而变化。我在这里寻找的是一个随提供给它的类型而变化的文字。也许模板专业化?!就像我希望编译器对字符串文字进行自动类型提升(想想标量参数,模板会毫不费力地工作,因为标量文字会自动提升为适当的类型。但对于字符串文字则不然)。 :(
-
@Mordachai:不能将
const char*升级为const wchar_t*或反之亦然的原因是,就编译器而言,它们是完全不同的类型。 -
慢动作配对编程 - 我喜欢它。
标签: c++ visual-studio templates unicode mfc