当我偶然发现一个曾经困扰过我几次的情景时,我正在编写一些单元测试。
我需要生成一些字符串来测试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&gt; = 7)std::wstring
的内容初始化L""
,因为它需要wchar_t L''
""s
无法正常工作,因为返回类型取决于类型charT
答案 0 :(得分:4)
简短的回答是否定的,你不能将两个generateStringData()
实现合并在一起。
一个是输出char
数据所必需的,另一个是输出wchar_t
数据所必需的。您可以use #define
macros减少代码中常见字符串文字的重复,但仍需要在L
实现中使用wchar_t
前缀,最好使用u8
前缀char
实现(为了确保数据实际上是UTF-8而不是编译器定义的),所以在运行时你仍然会在内存中使用单独的字符串。
即使您使用模板尝试合并这两个实现,您最终也需要使用模板特化来分离两种输出类型。
您最好只使用已有的重载(可能使用#define
来减少代码中的重复项),或者在运行时执行UTF转换(您希望避免)。在后一种情况下,您可以通过在应用启动时执行一次转换并缓存结果以便重复使用来减少测试运行的开销。
答案 1 :(得分:2)
如果 您只需要将纯ASCII编码为char
和wchar_t
s,那么您可以使用功能模板(无需专业化):
#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值。如果你有兴趣&#34;源字符串中的字符,实际上不会将它们转换为正确的UTF-16。
另请注意,您几乎肯定会在内存中找到四个字符串副本:可执行文件中的两个ASCII源字符串副本(来自函数模板的两个实例),以及{{1堆中有}和char
个副本。
但这可能不比预处理器版本差。使用预处理器,您最终可能会在可执行文件中同时使用wchar_t
和char
版本,以及堆中的wchar_t
和char
副本。< / p>
预处理器方法可以做的是帮助你绕过这个答案顶部的那个大<strong> if ;使用预处理器,您可以使用非ASCII字符。
[实施说明:最初这些作业使用wchar_t
和std::begin(entry.first)
,但其中包含字符串终结符作为字符串本身的一部分。]