Как написать оператор вставки потока для общего случая? (То есть для потоков `char` и` wchar_t`?) - PullRequest
4 голосов
/ 28 декабря 2010

Я реализую оператор вставки потока для моего класса. Я бы хотел, чтобы мой класс работал с узкими и широкими потоками. Я использую шаблон, чтобы разрешить такое поведение - и все не зависит от того, какой тип потока фактически используется, за исключением символьных литералов. Если это широкая строка, символьные литералы должны * L ставиться перед литералом, в противном случае - нет.

Есть ли способ связать такого рода вещи с параметром шаблона, чтобы мне не нужно было дублировать столько кода на этом?

(Я бы предпочел избегать преобразования символов из узкой в ​​широкую или из широкой в ​​узкую область во время выполнения, если это возможно.)

Пример того, что у меня сейчас есть - это шаблон, но он не будет работать с узкими символьными потоками из-за литералов широких символов:

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;
}

Ответы [ 2 ]

8 голосов
/ 29 декабря 2010

Если вам не нужны накладные расходы времени выполнения, я думаю, что, хотя некрасиво , в этом случае вам может помочь макрос.* с другим красивым макросом, чтобы еще больше уменьшить дублирование кода.то есть doselect2(" --> ") автоматически расширится до doselect(charT, " --> ").

1 голос
/ 29 декабря 2010

Что я делаю, так это вставляю только символ и преобразую их в широкий или узкий символ.Преобразование выполняется во время компиляции, и если вы используете только символы, которые равны в широкой и узкой кодировке, это работает.Это утомительно, но работает.

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(
    std::basic_ostream<charT, traits>& lhs,
    const Process& rhs
    )
{
    lhs << charT('P') << charT('r') << charT('o') << charT('c') << charT('e')
        << charT('s') << charT('s') << charT(' ') << charT('(') << charT('0')
        << charT('x') << std::setw(8) << std::hex << std::setfill(charT('0'))
        << rhs.GetId() << charT(')') << charT(' ');
    lhs << rhs.GetName() << std::endl;
    lhs << charT('C') << charT('o') << charT('m') << charT('m') << charT('a')
        << charT('n') << charT('d') << charT(' ') << charT('L') << charT('i')
        << charT('n') << charT('e') << charT(':') << charT(' ')
        << 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 << charT(' ') << charT('-') << charT('-') << charT('>') << 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 << charT(' ') << charT('-') << charT('-') << charT('>') << charT(' ')
            << it->second << std::endl;
    }
    return lhs;
}

Если у вас много строк, вы можете использовать другой шаблон, который вы будете специализировать на широком или узком типе символов и использовать для хранения строк.Это, однако, заставит вас продублировать ваши строки (и вы нарушите принцип СУХОГО).

template <typename charT>
struct ProcessInsertionOperatorHelper
{
    static const charT* const String1;
    static const charT* const String2;
    static const charT* const String3;
    static const charT* const String4;
};

template <>
const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String1 = L"Process (0x";
template <>
const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String2 = L") ";
template <>
const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String3 = L"Command Line: ";
template <>
const wchar_t* const ProcessInsertionOperatorHelper<wchar_t>::String4 = L" --> ";

template <>
struct ProcessInsertionOperatorHelper<char>
{
};

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(
    std::basic_ostream<charT, traits>& lhs,
    const Process& rhs
    )
{
    lhs << ProcessInsertionOperatorHelper<charT>::String1 << std::setw(8)
        << std::hex << std::setfill(L'0') << rhs.GetId()
        << ProcessInsertionOperatorHelper<charT>::String2;
    lhs << rhs.GetName() << std::endl;
    lhs << ProcessInsertionOperatorHelper<charT>::String3
        << 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 << ProcessInsertionOperatorHelper<charT>::String4
            << *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 << ProcessInsertionOperatorHelper<charT>::String4
            << it->second << std::endl;
    }
    return lhs;
}
...