问题描述
新功能:谢谢所有为我提供帮助的人!答案标记在下面,我在下面的问题中(q.v.)扩展了功能版本:
NEW: Thank you everyone who helped me with this! The answer is marked below, and I've expanded on the answer with a functioning version in my question, below (q.v.):
我似乎经常遇到这种情况(在更新我们的字符串实用程序库时):
I seem to be running into this situation a lot (while updating our string utilities library):
我需要一种可以同时用于char和wchar_t的模板的方法,该模板使用各种字符串文字.目前,我发现这具有挑战性,因为我不知道如何使用编译时方式将字符串文字更改为窄字符或宽字符.
I need a way to have a template which works for both char and wchar_t, which uses various string-literals. Currently I'm finding this challenging because I don't know how to have a compile-time way to alter string literals to be narrow or wide character.
请考虑以下基于TCHAR的功能:
For consideration, take the following TCHAR based function:
// 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")的问题.
Immediately we have a problem with the two string literals ('"', and "%c%s%c").
如果为CSTRING_T = CStringA,CHAR_T = char调用以上内容,那么上面的文字就可以了.但是,如果为CStringW和wchar_t调用它,那么我真的需要(L''和L"%c%c%c).
If the above is invoked for CSTRING_T = CStringA, CHAR_T = char, then the above literals are fine. But if it is invoked for CStringW and wchar_t, then I really need (L'"', and L"%c%c%c").
所以我需要某种方式来做类似的事情:
So I need some way to do something like:
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(字符串或字符文字)根据CHAR_T实际产生L"string"或"string"?
And that's where I am lost: What in the world can I do to make Literal(string-or-character-literal) that actually results in L"string" or "string" depending on CHAR_T?
有一百多个函数,其中许多函数较复杂,其中包含更多的字符串字面量,需要同时适用于窄字符串和宽字符串.无需复制每个这样的函数,然后将每个函数编辑为宽或窄,那么肯定有一种技术可以允许单个定义随CHAR_T的不同而改变?
There are over a hundred functions, many of them more complex with more string-literals in them, that need to be available both for narrow and wide strings. Short of copying every such function and then editing each one to either be wide or narrow, surely there is a technique that would allow a single definition that varies by CHAR_T?
我给出了Mark Ransom提供的混合宏+模板的答案,但是我想提供一个更完整的解决方案(对于所有关心的人),所以这里是:
I'm giving the answer to the hybrid macro + template that Mark Ransom supplied, but I wanted to include a more complete solution (for anyone who cared), so here it is:
// 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结合使用,从而使编写模板更容易/更易于阅读和阅读.理解:
In addition, I created some helpers to make writing templates that utilized this concept in conjunction with CStringT<> a bit easier / nicer to read & comprehend:
// 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变体的模板.例如:
With the above, it is possible to write templates which generate the correct CString variety based on CStringT<> or char/wchar_t arguments. For example:
// 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;
}
推荐答案
概念是使用宏来生成两种形式的文字char
和wchar_t
,然后让模板函数选择合适的形式对于上下文.
The concept is to use a macro to generate both forms of the literal, char
and wchar_t
, then let a template function choose which one is appropriate for the context.
请记住,模板函数实际上不会生成任何代码,除非您有其他代码对其进行调用.在大多数情况下,这无关紧要,但是对于库来说就如此.
Remember that template functions don't actually generate any code until you have other code that makes a call to them. Most of the time this doesn't matter, but it would for a library.
此代码未经测试,但我相信它将起作用.
This code is untested, but I believe it will work.
#define LITERAL(T,x) CString_traits<T>::choose(x, L##x)
template<typename T>
struct CString_traits
{
typedef char char_type;
static const char * choose(const char * narrow, const wchar_t * wide) { return narrow; }
static char choose(char narrow, wchar_t wide) { return narrow; }
};
template<>
struct CString_traits<CStringW>
{
typedef wchar_t char_type;
static const wchar_t * choose(const char * narrow, const wchar_t * wide) { return wide; }
static wchar_t choose(char narrow, wchar_t wide) { return wide; }
};
template <typename T>
inline void MakeQuoted(T & str, CString_traits<T>::char_type chQuote = LITERAL(T,'"'))
{
if (str.IsEmpty() || str[0] != chQuote)
str.Format(LITERAL(T,"%c%s%c"), chQuote, str, chQuote);
}
这篇关于模板和字符串文字以及UNICODE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!