Listing 2: Temperature.cpp

// My header
#include "Temperature.h"

#include <ostream>
#include <istream>
#include <stdexcept>

namespace Util {

// iword / pword index
const int Temperature::strm_index = std::ios::xalloc();

    
// manipulators
std::ostream&
Temperature::asK(std::ostream& os)
{
    os.pword(strm_index) = &_putK;
    return os;
};

std::ostream&
Temperature::asC(std::ostream& os)
{
    os.pword(strm_index) = &_putC;
    return os;
};

std::ostream&
Temperature::asF(std::ostream& os)
{
    os.pword(strm_index) = &_putF;
    return os;
};

std::ostream&
Temperature::show_scale(std::ostream& os)
{
    os.iword(strm_index) = 1;
    return os;
};

std::ostream&
Temperature::no_scale(std::ostream& os)
{
    os.iword(strm_index) = 0;
    return os;
};

// output formaters
std::ostream&
Temperature::_putK(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inK();
    if (show_scale) os << 'K';
    return os;
}

std::ostream&
Temperature::_putC(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inC();
    if (show_scale) os << 'C';
    return os;
}

std::ostream&
Temperature::_putF(std::ostream& os, Temperature obj, long flags)
{
    bool show_scale = flags bitand 1;
    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << obj.inF();
    if (show_scale) os << 'F';
    return os;
}

// ostream inserter
std::ostream&
operator<<(std::ostream& os, Temperature obj)
{
    typedef std::ostream& (*Formater)(std::ostream&, Temperature, long);
    int idx = Temperature::strm_index;
    Formater fmt = Formater(os.pword(idx));
    if (!fmt) {        // no format specified
        os.setstate(std::ios::failbit);  // may throw exception
        return os;
    }

    return fmt(os, obj, os.iword(idx));
}

// istream extractor
std::istream&
operator>>(std::istream& is, Temperature& obj)
{
    // Assumed to be in format 'nn.nX' where 'X' is F/C/K
    // Read the number
    float val = -1.0;
    is >> val;
    
    // Get next character
    int ch = is.get();
    switch (char(ch)) {
    case 'F':
        obj = Temperature::inF(val);
        break;
    case 'C':
        obj = Temperature::inC(val);
        break;
    case 'K':
        obj = Temperature::inK(val);
        break;
    default:
        is.setstate(std::ios::failbit);  // may throw exception
        obj = Temperature::inK(-1.0);
    }
    return is;
}

    
} //> namespace