我移植使用的Xerces-C用于XML处理从Windows / VC ++到Linux / G ++一个代码库。
在Windows中,的Xerces-C使用wchar_t
的字符类型XmlCh
。 这使得人们使用std::wstring
和字符串文字L""
语法。
在Linux / G ++, wchar_t
是32位和Xerces-C使用unsigned short int
(16位)作为字符类型XmlCh
。
我沿着这条赛道开始了:
#ifdef _MSC_VER
using u16char_t = wchar_t;
using u16string_t = std::wstring;
#elif defined __linux
using u16char_t = char16_t;
using u16string_t = std::u16string;
#endif
不幸的是, char16_t
和unsigned short int
是不等价的和他们的指针不是隐式转换。 因此,通过u"Hello, world."
到Xerces的功能仍然会导致无效的转换错误。
它开始看起来像我将不得不显式强制每个字符串我传递给Xerces的功能。 但我做之前,我想问如果有谁知道一个更理智的方式来编写跨平台的Xerces-C代码。
答案是否定的,没有人对如何做到这一点是一个好主意。 对于其他人谁发现这个问题,这是我想出了:
#ifdef _MSC_VER
#define U16S(x) L##x
#define U16XS(x) L##x
#define XS(x) x
#define US(x) x
#elif defined __linux
#define U16S(x) u##x
#define U16XS(x) reinterpret_cast<const unsigned short *>(u##x)
inline unsigned short *XS(char16_t* x) {
return reinterpret_cast<unsigned short *>(x);
}
inline const unsigned short *XS(const char16_t* x) {
return reinterpret_cast<const unsigned short *>(x);
}
inline char16_t* US(unsigned short *x) {
return reinterpret_cast<char16_t *>(x);
}
inline const char16_t* US(const unsigned short *x) {
return reinterpret_cast<const char16_t*>(x);
}
#include "char16_t_facets.hpp"
#endif
namespace SafeStrings {
#if defined _MSC_VER
using u16char_t = wchar_t;
using u16string_t = std::wstring;
using u16sstream_t = std::wstringstream;
using u16ostream_t = std::wostream;
using u16istream_t = std::wistream;
using u16ofstream_t = std::wofstream;
using u16ifstream_t = std::wifstream;
using filename_t = std::wstring;
#elif defined __linux
using u16char_t = char16_t;
using u16string_t = std::basic_string<char16_t>;
using u16sstream_t = std::basic_stringstream<char16_t>;
using u16ostream_t = std::basic_ostream<char16_t>;
using u16istream_t = std::basic_istream<char16_t>;
using u16ofstream_t = std::basic_ofstream<char16_t>;
using u16ifstream_t = std::basic_ifstream<char16_t>;
using filename_t = std::string;
#endif
char16_t_facets.hpp
具有模板特的定义std::ctype<char16_t>
std::numpunct<char16_t>
std::codecvt<char16_t, char, std::mbstate_t>
因此有必要将这些添加到全局区域,伴随着std::num_get<char16_t>
和std::num_put<char16_t>
但没有必要为这些提供专业化)。 对于代码codecvt
是很困难的唯一位,以及合理的模板可以在GCC 5.0库中找到(如果你使用GCC 5,你并不需要提供codecvt
专业化因为它已经在图书馆)。
一旦你完成了所有这一切,对char16_t
流将正常工作。
然后,每次你定义一个宽字符串,而不是L"string"
,写U16S("string")
每一次你通过一个字符串Xerces的时间,写XS(string.c_str())或U16XS(“串”)的文字。 每次你从Xerces的得到一个字符串返回时,将其转换回为u16string_t(US(call_xerces_function()))
请注意,它也有可能的Xerces-C编译设定为char16_t字符类型。 这消除了许多上述所需的工作。 但你将无法使用任何其他库又依赖于的Xerces-C系统。 链接到任何这样的库将导致链接错误(因为改变字符类型改变很多了Xerces函数签名)。