c++ - 如何为一般情况编写流插入运算符? (也就是说,对于 `char` 和 `wchar_t` 流?)

标签 c++ templates unicode iostream

我正在实现 stream insertion operator对于我的一个类。我希望我的类(class)能够同时使用窄流和宽流。我正在使用一个模板来允许这种行为——除了字 rune 字之外,一切都与实际使用的流类型无关。如果它是一个宽字符串,则字 rune 字需要在文字前面加上 L,否则不需要。

有没有办法将这种东西键入模板参数,这样我就不需要在上面复制这么多代码?

(如果可能,我宁愿避免在运行时执行窄到宽字符或宽到窄字符转换。)

我目前拥有的示例——它是一个模板,但由于宽字 rune 字,它不适用于窄字符流:

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(
    std::basic_ostream<charT, traits>& lhs,
    const Process& rhs
    )
{
    lhs << L"Process (0x" << std::setw(8) << std::hex
        << std::setfill(L'0') << rhs.GetId() << L") ";
    lhs << rhs.GetName() << std::endl;
    lhs << L"Command Line: " << rhs.GetCmdLine() << std::endl;
    const std::vector<Thread>& threads = rhs.GetThreads();
    for (std::vector<Thread>::const_iterator it = threads.begin(); 
        it != threads.end(); ++it)
    {
        lhs << L" --> " << *it << std::endl;
    }
    const std::map<void *, Module>& modules = rhs.GetModules();
    for (std::map<void *, Module>::const_iterator it = modules.begin(); 
        it != modules.end(); ++it)
    {
        lhs << L" --> " << it->second << std::endl;
    }
    return lhs;
}

最佳答案

如果您不想要运行时开销,我认为尽管丑陋,宏在这种情况下可以为您提供帮助。

template <typename T>
inline const T* select(const char* narrow, const wchar_t* wide);

template <>
inline const char* select<char>(const char* narrow, const wchar_t* /*wide*/)
{
    return narrow;
}

template <>
inline const wchar_t* select<wchar_t>(const char* /*narrow*/, const wchar_t* wide)
{
    return wide;
}

#define doselect(T, str) select<T>(str, L ## str)

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(
    std::basic_ostream<charT, traits>& lhs,
    const Process& rhs
    )
{
    lhs << doselect(charT, "Process (0x") << std::setw(8) << std::hex
        << std::setfill(charT('0')) << rhs.GetId() << doselect(charT, ") ");
    lhs << rhs.GetName() << std::endl;
    lhs << doselect(charT, "Command Line: ") << rhs.GetCmdLine() << std::endl;
    const std::vector<Thread>& threads = rhs.GetThreads();
    for (std::vector<Thread>::const_iterator it = threads.begin(); 
        it != threads.end(); ++it)
    {
        lhs << doselect(charT, " --> ") << *it << std::endl;
    }
    const std::map<void *, Module>& modules = rhs.GetModules();
    for (std::map<void *, Module>::const_iterator it = modules.begin(); 
        it != modules.end(); ++it)
    {
        lhs << doselect(charT, " --> ") << it->second << std::endl;
    }
    return lhs;
}

您可以使用另一个不错的宏来扩展doselect,以进一步减少代码重复。即 doselect2("--> ") 会自动扩展为 doselect(charT, "--> ")

关于c++ - 如何为一般情况编写流插入运算符? (也就是说,对于 `char` 和 `wchar_t` 流?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4548826/

相关文章:

unicode - 未读取 golang unicode/norm 迭代器的最后一个 rune

python - JSON 加载返回 unicode 而不是字典

c++ - Linux 中编译的程序未检测到 fstream 中的 '\n' 换行符,而 Windows 运行时会检测到

Django 中的 Javascript 模板

c# - C# 中的模板

c++ - 重构模板类,使用它的嵌套类作为另一个类的模板参数

python - 只打印字符串的内容

java - 是否可以在 android studio 中编写纯 java/c++ 程序

c++ - token "<"之前的错误预期标识符

c++ - 在Windows上使用MinGW构建mysql-connector-c++-8.0.17-src