C++ 从相同的硬编码字符串文本初始化std::string和std::wstring

C++ 从相同的硬编码字符串文本初始化std::string和std::wstring,c++,string,unicode,C++,String,Unicode,我在编写一些单元测试时,偶然发现了一个场景,该场景已经让我遇到了好几次问题 我需要生成一些字符串来测试JSON编写器对象。因为writer同时支持UTF16和UTF8输入,所以我想用这两种输入来测试它 考虑以下测试: class UTF8; class UTF16; template < typename String, typename SourceEncoding > void writeJson(std::map<String, String> & dat

我在编写一些单元测试时,偶然发现了一个场景,该场景已经让我遇到了好几次问题

我需要生成一些字符串来测试JSON编写器对象。因为writer同时支持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>();
}
UTF8类;
UTF16类;
模板
void writeJson(标准::映射和数据)
{
//写入文件
}
无效generateStringData(标准::地图和数据)
{
emplace(“Lorem”,“Lorem Ipsum”只是印刷和排版行业的虚拟文本。”);
数据.emplace(“Ipsum”,“Ipsum”自16世纪以来一直是行业标准的虚拟文本,当时一位不知名的印刷商拿起一个打印工具,将其拼凑成一本打印样本书”);
data.emplace(“相反”,“与流行信仰相反,Lorem Ipsum不是简单的随机文本。它起源于公元前45年的一篇古典拉丁文学作品,距今已有2000多年”);
}
无效generateStringData(标准::地图和数据)
{
emplace(L“Lorem”,L“Lorem Ipsum只是印刷和排版行业的虚拟文本。”);
数据.emplace(L“Ipsum”,L“Ipsum”自16世纪以来一直是行业标准的虚拟文本,当时一位不知名的印刷商拿着一个打印工具,将其拼凑成一本打印样本书);
数据。emplace(L“相反”,L“与流行信仰相反,Lorem Ipsum不是简单的随机文本。它起源于公元前45年的一篇古典拉丁文学作品,距今已有2000多年历史”);
}
模板
void testWriter(){
地图数据;
generateStringData(数据);
writeJson(数据);
}
int main(){
testWriter();
testWriter();
}
除了duplicate
generateStringData()
方法之外,我设法很好地包装了所有内容我想知道是否可以将这两个
generateStringData()
方法组合成一个方法?

我知道我可以使用一个方法在UTF8中生成字符串,然后使用另一个方法将字符串转换为UTF16,但我正在尝试找出是否还有其他方法

我考虑/尝试了什么

  • 使用
    \u T()
  • 从非
    L”“
    的内容初始化
    std::wstring
    将不起作用,因为它需要一个wchar\t
  • 逐字符初始化字符将不起作用,因为它还需要
    L'
  • 使用
    “s
    将不起作用,因为返回类型取决于类型
    图表

简短的回答是否定的,您不能将这两个
generateStringData()
实现合并在一起

一个需要输出
char
数据,另一个需要输出
wchar\t
数据。您可以减少代码中常见字符串文本的重复,但仍然需要在
wchar\u t
实现中使用
L
前缀,最好在
char
实现中使用
u8
前缀(以确保数据实际上是UTF-8而不是编译器定义的),因此,在运行时,内存中仍然会有单独的字符串

即使要使用模板来尝试合并这两个实现,最终也需要使用模板专门化来分离这两种输出类型

您最好只使用已有的重载(可能使用
#define
s来减少代码中的重复),或者在运行时执行UTF转换(这是您想要避免的)。在后一种情况下,您可以通过在应用程序启动时执行一次转换并缓存结果以供重用来减少测试运行的开销。

如果您只需要将普通ASCII编码为
char
s和
wchar\u t
s,则可以使用函数模板(无需专门化):

#包括
#包括
#包括
#包括
模板
无效generateStringData(标准::地图和数据){
静态常量std::对条目[]={
{“Lorem”,“Lorem Ipsum只是一个虚拟文本…”,
{“Ipsum”,“Ipsum已成为行业标准…”
};
用于(常量自动输入和输入:输入){
数据放置(StringType(entry.first,entry.first+std::strlen(entry.first)),
StringType(entry.second,entry.second+std::strlen(entry.second));
}
}
int main(){
标准::映射ansi;
generateStringData(ansi);
地图范围;
generateStringData(广域);

std::cout UTF-8和UTF-16字符串对于给定的非ASCII文本不包含相同的字节。您的测试用例只包含7位ASCII,它们是无用的。@manni66,这些是一些伪值,这不是这个问题的本质…建议使用UTF-8来读/写与web相关的数据。如果必须使用UTF-16,请使用UTF-16编写文件-8行,并在整个文件上运行最终的UTF-16转换(如果文件大于2 gig,则会失败)@BarmakShemirani,这不是与web相关的数据。这是从Windows获取的信息,默认情况下,某些API使用wchar\u t。恐怕预处理器是唯一的选择。这让我非常惊讶……我认为在我读到这篇文章之前,永远不能使用
常量char*
文字来初始化
wstring
。@Edityouprofile:它实际上不是从
const char*
初始化
wstring
。它是从
char
s范围复制单个字符值,并依靠隐式转换将其转换为
wchar\t
s(或任何目标字符类型)。对于真正的7位ASCII值,隐式转换是正确的。
#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;
}