当我偶然发现一个已经使我烦恼几次的场景时,我正在编写一些单元测试。

我需要生成一些字符串来测试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
  • 按字符初始化char无效,因为它也需要L''
  • 由于返回类型取决于""s类型,因此无法使用charT
  • 最佳答案

    如果使用,则只需要将纯ASCII编码为charwchar_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源字符串的两个拷贝(来自功能模板的两个实例),堆中的charwchar_t拷贝。

    但这可能不会比预处理程序版本差。使用预处理器,最终可能会在可执行文件中同时包含charwchar_t版本,以及堆中的charwchar_t拷贝。

    预处理器方法可以做的是,如果位于此答案的顶部,则可以帮助您绕过那个大的;通过预处理器,可以使用非ASCII字符。

    [实现说明:最初,这些分配使用std::begin(entry.first)std::end(entry.first),但其中包括字符串终止符作为字符串本身的一部分。

    10-07 12:14
    查看更多