Оператор перегрузки << (unsigned char typedef as byte) - PullRequest
10 голосов
/ 15 августа 2011

Я хочу перегрузить (угнать?) ostream и basic_ostream<unsigned char>, чтобы он прекратил попытки отобразить октет (беззнаковый символ) в качестве печатного символа.

Я живу с cout и друзья выкладывают смайлики на экран слишком долго.И я устал работать с приведениями: hex << int(0xFF & b) << ....

Можно ли переопределить стандартное поведение?Я пробовал как шаблонные, так и не шаблонные переопределения.Они компилируются, но, кажется, не называются.

Ответы [ 6 ]

5 голосов
/ 15 августа 2011

Проблема в том, что уже есть

template<class charT, class traits>
std::basic_ostream<charT,traits>& 
operator<<(std::basic_ostream<charT,traits>&, charT);

в namespace std. Поскольку basic_ostream<> также находится в этом пространстве имен, ADL подхватывает его, когда вы выводите unsigned char. Добавление собственной перегрузки может сделать вызов оператора неоднозначным, иначе ваша перегрузка будет игнорироваться.

Но даже если бы это работало, это было бы хрупко, потому что если забыть одно включение, это может слегка изменить смысл кода без какой-либо диагностики от компилятора.
И еще: каждый программист, который рассматривает такой код, будет считать, что вызывается стандартный оператор (и никогда не думает о добавлении включения, когда он добавляет еще один оператор вывода в код).
Короче говоря, может быть лучше добавить функцию , делающую то, что вы хотите.

Разумной семантической альтернативой может быть добавление потокового манипулятора, который вызывает желаемый выходной формат. Хотя я не уверен, что это технически возможно.

4 голосов
/ 15 августа 2011

Люк правильный.

Более быстрая альтернатива вашему текущему подходу & mdash; если вы не возражаете против десятичного вывода & mdash; это продвигать символ до int:

unsigned char c = '!';
os << +c;

Я не понимаю, как это облагается налогом!

3 голосов
/ 15 августа 2011

Все верно, что то, о чем вы просите, не произойдет.

Лучшее, что вы можете сделать, это написать свой собственный манипулятор ввода / вывода (iomanip), чтобы творить чудесадля вас. В этом случае вам нужна функция, которая принимает unsigned char (хотя я бы настоятельно рекомендовал бы использовать uint8_t из <stdint.h>).

#include <stdint.h>
#include <ostream>

class asHex
{
public:
    asHex(uint8_t theByte): value(theByte) {}
    void operator()(std::ostream &out) const 
        { std::ios::fmtflags oldFlags = out.flags; out << std::hex 
              << std::setw(2) << std::setfill('0') << std::uppercase << theByte; 
          out.flags(oldFlags); }
private:
    uint8_t theByte;
};

std::ostream& operator<<(std::ostream &out, asHex number)
{
    number(out); return out;
}

Затем вы можете написать:

cout << asHex(myByte);

Вы можете добавить конструкторы в asHex или даже сделать из них шаблонный класс для поддержки 16, 32 и других битов.

(ДаЯ знаю, <stdint.h> не является официальным заголовком C ++, но я предпочел бы иметь его определения в глобальном пространстве имен вместо std:: без необходимости делать using namespace std;, который выводит все в глобальномПространство имен.)

3 голосов
/ 15 августа 2011
#include <iostream>
#include <string>       // std::char_traits

typedef unsigned char       UChar;
typedef UChar               Byte;

typedef std::char_traits<char>      CharTraits;
typedef std::char_traits<wchar_t>   WCharTraits;

typedef std::basic_ostream< char, CharTraits >      CharOStream;
typedef std::basic_ostream< wchar_t, WCharTraits >  WCharOStream;

CharOStream& operator<<( CharOStream& stream, UChar v )
{
    return stream << v+0;
}

int main()
{
    char const      c   = 'c';
    UChar const     u   = 'u';

    std::cout << c << '\n' << u << std::endl;
}

Это прекрасно работает с MSVC 10.0 и MinGW g ++ 4.4.1, и оно корректно компилируется с Comeau Online, поэтому я считаю, что формально все в порядке.

Приветствия и hth.,

1 голос
/ 15 августа 2011

Вы не можете напрямую изменить поведение std::cout.Было бы слишком подвержено ошибкам, если какой-либо dev-код может изменить поведение стандартной библиотеки, используемой другим кодом.

Вы можете создать свой собственный класс, который имитирует поведение std::coutи вместо этого используйте этот объект.

class SpecialCout
{
    template <typename T>
    friend SpecialCout& operator<< ( SpecialCout const& scout, T const &t )
    {
        // Do any adjustments to t here, or decide to return early.

        std::cout << t;
        return *this;
    }

};

extern SpecialCout scout;
1 голос
/ 15 августа 2011

Благодаря ADL будет вызван стандарт operator<<. Попробуйте явно уточнить ваш звонок:

::operator<<(os, 42);
...