当我偶然发现一个已经使我烦恼几次的场景时,我正在编写一些单元测试。
我需要生成一些字符串来测试JSON编写器对象。由于编写器支持UTF16和UTF8输入,因此我想同时使用它们进行测试。
考虑以下测试:
class UTF8;
class UTF16;
template < typename String, typename SourceEncoding >
void writeJson(std::map<String, String> & data)
{
// Write to file
}
void generateStringData(std::map<std::string, std::string> & data)
{
data.emplace("Lorem", "Lorem Ipsum is simply dummy text of the printing and typesetting industry.");
data.emplace("Ipsum", "Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book");
data.emplace("Contrary", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old");
}
void generateStringData(std::map<std::wstring, std::wstring> & data)
{
data.emplace(L"Lorem", L"Lorem Ipsum is simply dummy text of the printing and typesetting industry.");
data.emplace(L"Ipsum", L"Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book");
data.emplace(L"Contrary", L"Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old");
}
template < typename String, typename SourceEncoding >
void testWriter() {
std::map<String, String> data;
generateStringData(data);
writeJson<String, SourceEncoding>(data);
}
int main() {
testWriter<std::string, UTF8>();
testWriter<std::wstring, UTF16>();
}
除了重复的
generateStringData()
方法,我设法很好地包装了所有内容。 并且我想知道是否可以将generateStringData()
的两个方法合并为一个方法? 我知道我可以使用一种方法在UTF8中生成字符串,然后使用另一种方法将字符串转换为UTF16,但是我试图找出是否还有另一种方法。
我考虑过/尝试过什么?
_T()
或TCHAR
或#ifdef UNICODE
将无济于事,因为我需要在支持Unicode(例如Win> = 7)的同一平台上同时使用这两种口味std::wstring
的东西初始化L""
将不起作用,因为它期望wchar_t L''
""s
类型,因此无法使用charT
最佳答案
如果使用,则只需要将纯ASCII编码为char
和wchar_t
,则可以使用功能模板来实现(无特殊化):
#include <iostream>
#include <map>
#include <string>
#include <utility>
template <typename StringType>
void generateStringData(std::map<StringType, StringType> &data) {
static const std::pair<const char *, const char *> entries[] = {
{ "Lorem", "Lorem Ipsum is simply dummy text ..."},
{ "Ipsum", "Ipsum has been the industry's standard ..."}
};
for (const auto &entry : entries) {
data.emplace(StringType(entry.first, entry.first + std::strlen(entry.first)),
StringType(entry.second, entry.second + std::strlen(entry.second)));
}
}
int main() {
std::map<std::string, std::string> ansi;
generateStringData(ansi);
std::map<std::wstring, std::wstring> wide;
generateStringData(wide);
std::cout << ansi["Lorem"] << std::endl;
std::wcout << wide[L"Lorem"] << std::endl;
return 0;
}
这仅是因为任何ASCII字符的
wchar_t
版本只是扩展到16位的ASCII值。如果源字符串中包含“有趣的”字符,则实际上不会将它们转换为正确的UTF-16。还要注意,您几乎肯定会在内存中得到字符串的四个拷贝:可执行文件中的ASCII源字符串的两个拷贝(来自功能模板的两个实例),堆中的
char
和wchar_t
拷贝。但这可能不会比预处理程序版本差。使用预处理器,最终可能会在可执行文件中同时包含
char
和wchar_t
版本,以及堆中的char
和wchar_t
拷贝。预处理器方法可以做的是,如果位于此答案的顶部,则可以帮助您绕过那个大的;通过预处理器,可以使用非ASCII字符。
[实现说明:最初,这些分配使用
std::begin(entry.first)
和std::end(entry.first)
,但其中包括字符串终止符作为字符串本身的一部分。