Norman said:
This is something that has puzzled me for a while. How does C++ define
skipws and noskipws
in such a way that they can be used as pseudo-variables that setf and unsetf
a flag?
The reason I ask is that I am defining a class for unlimited-length integers
and have defined a
friend operator overload of << and I would like the user to be able to turn
on and turn off the
printing of commas delimiting groups of three digits.
Here's a way to allow the user to turn on and off the printing of
commas. With a system like this in place, you can just write:
ExtendedInteger ei(100);
cout << noCommas << ei << endl;
cout << commas << ei << endl;
I have not implemented a full extended integer type, just the basics
necessary to demonstrate the use of the noCommas and commas things.
/* file commaprint.hpp */
#ifndef H_COMMAPRINT
#define H_COMMAPRINT
#include <iostream>
class Comma {};
class NoComma {};
extern Comma commas;
extern NoComma noCommas;
class ExtendedInteger
{
private:
long value;
public:
ExtendedInteger(long v);
friend std:
stream&
operator<<(std:
stream& s, const ExtendedInteger& ei);
ExtendedInteger& operator/=(const ExtendedInteger& rhs);
ExtendedInteger operator% (const ExtendedInteger& rhs) const;
bool operator!=(const ExtendedInteger& rhs) const;
int getIntValue() const;
};
std:
stream&
operator<<(std:
stream& s, const Comma& c);
std:
stream&
operator<<(std:
stream& s, const NoComma& nc);
#endif
/* end file commaprint.hpp */
/* file commaprint.cpp */
#include "commaprint.hpp"
#include <iostream>
#include <string>
static bool enableCommas;
Comma commas;
NoComma noCommas;
std:
stream&
operator<<(std:
stream& s, const Comma& c)
{
enableCommas = true;
return s;
}
std:
stream&
operator<<(std:
stream& s, const NoComma& nc)
{
enableCommas = false;
return s;
}
ExtendedInteger::ExtendedInteger(long a)
: value(a)
{}
std:
stream&
operator<<(std:
stream& s, const ExtendedInteger& ei)
{
ExtendedInteger a = ei;
std::string output;
char buf[5];
const char *format = enableCommas ? "%03d," : "%03d";
do
{
sprintf(buf, format, (a % 1000).getIntValue());
output.insert(0, buf);
a /= 1000;
}
while(a != 0);
if(enableCommas) output.erase(output.end() - 1);
if((output.begin())[0] == '0') output.erase(output.begin());
if((output.begin())[0] == '0') output.erase(output.begin());
return s << output;
}
ExtendedInteger&
ExtendedInteger:
perator/=(const ExtendedInteger& rhs)
{
value /= rhs.value;
return *this;
}
ExtendedInteger
ExtendedInteger:
perator% (const ExtendedInteger& rhs) const
{
return value % rhs.value;
}
bool
ExtendedInteger:
perator!=(const ExtendedInteger& rhs) const
{
return value != rhs.value;
}
int
ExtendedInteger::getIntValue() const
{
assert(value >= INT_MIN && value <= INT_MAX);
return int(value);
}
/* end file commaprint.cpp */
/* file test_driver.cpp */
#include "commaprint.hpp"
#include <iostream>
using namespace std;
int main(void)
{
ExtendedInteger i(1000000000);
do
{
i /= 10;
cout << " " << noCommas;
cout.width(12);
cout << i << " " << commas;
cout.width(14);
cout << i << endl;
}
while(i != 0);
return 0;
}
/* end file test_driver.cpp */