Adding new flags to control an ostream

Hi all

I have a nice class for tracking units-of-measure along with numerical values.

I have a simple output method accompanying this class which I can use to make the units show whenever a value is outputted to an ostream, as shown below.

My question: instead of using the ios_base::showbase flag (which is really intended for something completely different), can I create a new flag that is guaranteed to work on all platforms, that won't clash with existing flags, and which can safely be set with the 'stream.flags()' method?

What would be the model approach here?

Any suggestions appreciated.

JP

---------------------8<------------------

#define DEFINE_OUTPUT_METHOD(MM,LL,TT,KK,II,UNITS) \
            inline \
            std::ostream& operator <<(std::ostream &os,const Units<MM,LL,TT,KK,II> &u){ \
                  double d = *reinterpret_cast<const double*>(&u); \
                  os << d; \
                  os.flags() & std::ios_base::showbase && os << " " << UNITS; \
                  return os; \
            }

DEFINE_OUTPUT_METHOD(0, 1, 0, 0, 0, "m");
DEFINE_OUTPUT_METHOD(0, 0, 1, 0, 0, "s");
DEFINE_OUTPUT_METHOD(0, 1, -1, 0, 0, "m/s");
LVL 7
jdpipeAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jdpipeAuthor Commented:
To clarify, this is how I use the above:

  Length L=5 * metre;
  cerr.flags(ios_base::showbase);
  cerr << "The car's length is "  << L << endl;

This would output:

  The car's length is 5 m
0
SteHCommented:
My approach would be to control the output of that class. Set a flag of that class and overwrite the <<operator () of that class to modify the oputput to your needs. Don't touch the well tested stream classes.
0
SteHCommented:
So your code should look like
Length L = 5, "metre";
L.flag (showunit);
cout << The car's length is " << L << endl;
0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

rstaveleyCommented:
You may be looking for xalloc and iword (or if you want to make it more complicated pword).

Here's a way of handling display units with a standard length class.

--------8<--------
#include <iostream>
#include <iomanip>
#include <string>

// Globals for display units
namespace display {

      // Allocate our global ios_base::iword index for display units
      const int index = std::ios_base::xalloc();

      // Metres/Yards
      enum Units {Metres,Yards};

      // Get the ostream's display units
      template<typename C>
        inline Units get_units(std::basic_ostream<C>& os)
      {
            return static_cast<Units>(os.iword(index));
        }

      // Set the ostream's display unitys
        template<typename C>
      inline void set_units(std::basic_ostream<C>& os,Units value)
      {
            os.iword(index) = value;
      }

      // A manipulator to set the verbosity level
      class units {

            const Units value;

            template<typename C>
            friend std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os,const units &u)
            {
                  set_units(os,u.value);
                  return os;
            }

      public:
            units(Units value) : value(value) {}
      };

} // display namespace

// Class for storing length
class StandardLength {

      double length;            // Internally stored as metres
      template<typename C>
            friend std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os,const StandardLength& distance);

public:
      StandardLength() {}
      StandardLength(double standard_length) : length(standard_length) {}

      // Construct a StandardLength in yards
      static StandardLength Yards(double yards_length)
      {
            return StandardLength(yards_length/0.9144);
      }

      // Construct a StandardLength in metres
      static StandardLength Metres(double metres_length)
      {
            return StandardLength(metres_length);
      }

};

// Display the StandardLength
template<typename C>
std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os,const StandardLength& distance)
{
      return os << (display::get_units(os) == display::Yards ? distance.length*0.9144 : distance.length);
}

int main()
{
      StandardLength race_length = StandardLength::Metres(100);
      std::cout
            << "The race is "
            << display::units(display::Yards)
            << race_length
            << " yards, which is "
            << display::units(display::Metres)
            << race_length
            << " metres\n";
}
--------8<--------

BTW... Don't trust my metres/yards conversion - this was a quick hack :-)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jdpipeAuthor Commented:
Thanks for the tips you guys...

STeH, this units class which I have needs to add zero overhead to storage and arithmetic operations, so I don't think that I can use a flag on top of the Units class, unless you had some clever way of doing it with static variables or something... But even then, I might want units being output in one stream, but not in another. For example, if I have a console window with some live results, showing units, but also afile with some tab-separated values. I would want both streams to keep their correct settings.

rstaveley, that stuff looks pretty good. I'm not familiar with xalloc and iword, I'll read up on those, check out your code, and get back to you.

Thanks again
JP
0
rstaveleyCommented:
> // A manipulator to set the verbosity level

That stray comment, which shouldn't be there, was left over from the facility for which I last used xalloc/iword. I had a flag which I put into the output stream to specify the verbosity of my debug.

I dug this stuff out of Standard C++ IOStreams and Locales by Langer and Kreft, which is worth flipping through, if you've got access to a library.
0
itsmeandnobodyelseCommented:
Actuall, i don't know why you are using 'showbase' flag:

I compiled using

#define DEFINE_OUTPUT_METHOD(MM,LL,TT,KK,II,UNITS) \
          inline \
          std::ostream& operator <<(std::ostream &os,const Units<MM,LL,TT,KK,II> &u){ \
               double d = *reinterpret_cast<const double*>(&u); \
               os << d; \
               /*os.flags() & std::ios_base::showbase && */os << " " << UNITS; \
               return os; \
          }

DEFINE_OUTPUT_METHOD(0, 1, 0, 0, 0, "m");
DEFINE_OUTPUT_METHOD(0, 0, 1, 0, 0, "s");
DEFINE_OUTPUT_METHOD(0, 1, -1, 0, 0, "m/s");

          Velocity v = 60. * kilometre / hour;
         
          Length x = 250. * kilometre;
         
          Time t = x / v;
          Length z = metre + metre;
          Units<0, 0, 0, 0, 0> unitless = 123.4;
          z = unitless * z;

          cerr << "The time taken to travel " << x << " at speed " << v << " is " << t << endl;
            // cerr.flags(ios_base::showbase);
            cerr << "The car's length is "  << z << endl;

not using any flag, and the output was fine:

The time taken to travel 250000 m at speed 16.6667 m/s is 15000 s
The car's length is 2 m

Regards, Alex
0
jdpipeAuthor Commented:
The idea here is to be able to safely define a flag which can be used to turn on and off the display of units. I originally thought I would dodgily re-use the 'showbase' flag usually reserved (I think) for showing 0x (or whatever it is) at the start of binary values.

I think rstaveley's approach with 'iword' is going to be the right one.

JP
0
rstaveleyCommented:
I vote for rstaveley's approach too ;-)
0
itsmeandnobodyelseCommented:
I also, though that below looks simpler and runs on my VC6 system:

enum { showunit = ios_base::showbase };

#define DEFINE_OUTPUT_METHOD(MM,LL,TT,KK,II,UNITS) \
          inline \
          std::ostream& operator <<(std::ostream &os,const Units<MM,LL,TT,KK,II> &u){ \
               double d = *reinterpret_cast<const double*>(&u); \
               os << d; \
               os.flags() & showunit && os << " " << UNITS; \
               return os; \
          }

DEFINE_OUTPUT_METHOD(0, 1, 0, 0, 0, "m");
DEFINE_OUTPUT_METHOD(0, 0, 1, 0, 0, "s");
DEFINE_OUTPUT_METHOD(0, 1, -1, 0, 0, "m/s");


int main(int argc, char *argv[]){
   
     Velocity v = 60. * kilometre / hour;
     Length x = 250. * kilometre;
     Time t = x / v;
     Length z = metre + metre;
     Units<0, 0, 0, 0, 0> unitless = 123.4;
     z = unitless * z;
     cerr << "The time taken to travel " << x << " at speed " << v << " is " << t << endl;
 
     cerr.flags(showunit);
     cerr << "The car's length is "  << z << endl;
         
     return 0;
}

Regards, Alex
0
itsmeandnobodyelseCommented:
The reason why the above works is:

// extract from xiosbase header

        enum _Fmtflags {skipws = 0x0001, unitbuf = 0x0002,
                uppercase = 0x0004, showbase = 0x0008,
                showpoint = 0x0010, showpos = 0x0020,
                left = 0x0040, right = 0x0080, internal = 0x0100,
                dec = 0x0200, oct = 0x0400, hex = 0x0800,
                scientific = 0x1000, fixed = 0x2000, boolalpha = 0x4000,
                adjustfield = 0x01c0, basefield = 0x0e00,
                floatfield = 0x3000, _Fmtmask = 0x7fff, _Fmtzero = 0};
         ...
        _BITMASK(_Fmtflags, fmtflags);  // ==> typedef int fmtflags;
         ...
         fmtflags flags(fmtflags _Nf)
         {fmtflags _Of = _Fmtfl;
           _Fmtfl = _Nf & _Fmtmask;
           return (_Of); }


By switching on and off just before and after Units elements, you could avoid influences on other output elements:

      cerr << "The time taken to travel " 
            << setiosflags(showunit) << x  << resetiosflags(showunit)
           << " at speed " << v << " is " << t << endl;

gives the following output:

The time taken to travel 250000 m at speed 16.6667 is 15000

Regards, Alex
0
guitaristxCommented:
Why not derive yourself a class from ostream, add the new flag in the derived class, and let everything else pass-through to the base class?
0
jdpipeAuthor Commented:
Would that work, guitaristx?

I don't want to have to change the stream I'm outputting to; I want to be able to write

stringstream s;
s << displayunits << length << endl;

and

cerr << displayunits << speed << endl;

So I wouldn't have thought I'd want to overload the stream classes...

JP
0
SteHCommented:
I doubt that you want to derive a new stream class. Only the << operator needs to be overloaded in the tracking units class.

class track {
 [snip]

 bool bShowUnits; // this can be either static of normal member variable: a static would be good to switch unit output for all class objects.
                          // whereas a normal member allows to change output for each object indiviually.
public:
 friend ostream& operator<< (ostream&, track& tr1);
}

ostream& operator << (ostream& os, track& tr1)
{
  if (true == track::bShowUnits) // or (true == tr1.bShowUnits) for non static member var
     os << tr1.value << " " << tr1.unit;
  else
     os << tr1.value;

  return os;
}

0
guitaristxCommented:
If it was me implementing it, I would:

create a function:

void displayunits(void)
{
     if(app_globals::disp_units == true) app_globals::disp_units = false;
     else app_globals::disp_units == true;
}

And another so that you can use it:

ostream& operator <<(ostream& out, void (*func)(void) )
{
     func();
     return out;
}

Then, create output operators for all the types that you want to assign units to:

ostream& operator<<(ostream& out, const myType&obj)
{
     if(app_globals::disp_units)
     {
            //display with units
            out << obj.value << " " << obj.units;
     }
      else
      {
            //display without units
            out << obj.value;
      }

       return out;
}

There are some assumptions; one being that you've created an output operator for your "units" type.  This would be the easiest way, IMHO.  You might create disp_units as a public static member of your units class.
0
jdpipeAuthor Commented:
Guitaristx

The units class I'm using here is one modified from http://www.embedded.com/shared/printableArticle.jhtml?articleID=9900094
you can see the code in current form at

http://cvs.sourceforge.net/viewcvs.py/freesteam/freesteam/units.h?rev=1.9&view=markup

The aim is to have zero runtime overhead on the units class. It's purely template related stuff which creates the output operator. Therefore there is no 'obj.units'.

Also, I want the display of units to be individually switched per stream. So I can have one stream open with units being written out, and another with no units being written.

JP
0
guitaristxCommented:
Wow....

Okay, after looking at your code, I'm going to recommend my original suggestion - overload the ostream class.  However, you may run into problems, since by overloading the class, you're making a subclass of ostream.  This being said, most people don't use ostream, they use subclasses of it (ofstream, ostringstream, etc).

What I'm thinking is something like this (and, unfortunately, you'll have to make overloads for all of the ostream-derived classes that you want to use, unless you want to get into multiple-inheritance):

class myofstream : public ofstream
{
protected:
     bool showunits;
public:
     void setShowUnits(bool set);
}

Now, make sure that you have overloaded output operators for your derived stream class(es).

Now, check out this URL:
http://www.informit.com/articles/article.asp?p=171014&seqNum=2
for instructions on how to implement a stream manipulator.  Manipulators are functions that operate on streams using the stream insertion operator (<<).  Now, you should be able to set this up so you can do this:

myofstream str("myfile.txt");
Units x = /*some value*/;
str << showunits(true) << x << endl;
str << showunits(false) << x << endl;

Is this the end result you're looking for?
0
jdpipeAuthor Commented:
Yeah except I don't want to overload the stream classes, seems like a lot of clutter.

What about rstaverley's xalloc and iword suggestions?

JP
0
rstaveleyCommented:
Do you need any help with xalloc/iword, JP?
0
jdpipeAuthor Commented:
Not abandoned, just a work in progress... I am interested in the answer but I haven't had a chance to test this xalloc/iword stuff
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.