Listing 5 — Temperature.cpp (alt)

// My header
#include "Temperature.h"

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

namespace Util {

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

// Facet id
std::locale::id            Temperature::punct::id;

// static facets
Temperature::punct        Temperature::punct_asK(&Temperature::inK, 'K');
Temperature::punct        Temperature::punct_asC(&Temperature::inC, 'C');
Temperature::punct        Temperature::punct_asF(&Temperature::inF, 'F');


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

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

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

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

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


// ostream inserter
std::ostream&
operator<<(std::ostream& os, Temperature obj)
{
    int idx = Temperature::strm_index;
    const Temperature::punct* fac =
        reinterpret_cast<Temperature::punct*>(os.pword(idx));

    if (not fac) {
        std::locale loc = os.getloc();
        bool found = std::has_facet<Temperature::punct>(loc);
        if (not found) {
            os.setstate(std::ios::failbit);    // may throw exception
            return os;
        }
        fac = &std::use_facet<Temperature::punct>(loc);
    }

    bool show_scale = os.iword(idx) bitand 1;

    int width = os.width();
    if (show_scale and width > 0) 
        os.width(width-1);
        
    os << fac->value(obj);
    if (show_scale) os << fac->scale();
    return os;
}

// 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