模板和字符串文字和UNICODE

Mor*_*hai 4 c++ unicode mfc templates visual-studio

新:感谢所有帮助过我的人!答案在下面标出,我在下面(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);
}
Run Code Online (Sandbox Code Playgroud)

我想模板化它:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

我们立即遇到两个字符串文字('"'和"%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);
}
Run Code Online (Sandbox Code Playgroud)

这就是我迷失的地方:我可以做什么来制作Literal(字符串或字符文字)实际上导致L"字符串"或"字符串"取决于CHAR_T?

编辑:有超过一百个函数,其中许多函数更复杂,其中包含更多的字符串文字,这些函数需要同时适用于窄字符串和宽字符串.如果没有复制每个这样的功能,然后将每个功能编辑为宽或窄,那么肯定有一种技术允许单个定义因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
Run Code Online (Sandbox Code Playgroud)

另外,我创建了一些帮助程序来编写模板,将这个概念与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
Run Code Online (Sandbox Code Playgroud)

通过上述内容,可以编写基于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;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*som 5

这个概念是使用宏来生成文字的两种形式,char并且wchar_t,然后让一个模板函数选择哪一个适合的环境.

请记住,在您有其他代码调用它们之前,模板函数实际上不会生成任何代码.大多数时候这并不重要,但它适用于图书馆.

此代码未经测试,但我相信它会起作用.

#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);
}
Run Code Online (Sandbox Code Playgroud)

  • 无论如何,我不是语言纯粹主义者.我想要高度可用的代码,这看起来很有希望.我会试一试,看看能否让它发挥作用.在一个成千上万的世界中,不得不忍受一个额外的宏(Win32编程),这根本不是一个缺点. (2认同)