Connecting Tech Pros Worldwide Forums | Help | Site Map

Need manipulator to set maximum I/O width

Johanus Dagius's Avatar
Newbie
 
Join Date: Jun 2007
Posts: 3
#1: Jun 22 '07
I've written a lot of C programs but only a few in C++. In C you can set both the minimum and maximum width of a formatted I/O output by using standard printf() formats. For example, if I have a very large string and I only want to print out the first 10 chars I can do this in C:
Expand|Select|Wrap|Line Numbers
  1. printf("s=%.10s\n", very_long_string).
How do I do this with C++ manipulators? I've tried std::setw(width), but it seems to control only the *minimum* width, not the max. I'm looking for something like in C++:

Expand|Select|Wrap|Line Numbers
  1. std::cout << std::maxw(10) << very_long_string << std:endl;
I know there are many "work-arounds" such as using substr(), but that only works with std::string. I often work with plain old c-strings.

I've been told that manipulators can mimic anything that printf() does, but it seems they can't even constrain fields to some specified size! Correct me if I'm wrong.

Tnx, Johanus

Moderator
 
Join Date: Mar 2007
Location: North Bend Washington USA
Posts: 5,375
#2: Jun 22 '07

re: Need manipulator to set maximum I/O width


Then write your own manipulator. Like endl. It's just a function with this prototype:
Expand|Select|Wrap|Line Numbers
  1. ostream& MyFunction(ostream&);
  2.  
For example suppose you want five asterisks to appear:
Expand|Select|Wrap|Line Numbers
  1. ostream& FiveStars(ostream& arg)
  2. {
  3.     arg << "*****";
  4.     return arg;
  5. }
  6.  
Then you call it by address:

Expand|Select|Wrap|Line Numbers
  1. cout << FiveStars << " Important! " << FiveStars << endl;
  2.  
The ostream::operator<<(ostream&, ostream& (*fp)(ostream&) ) just calls the function by address passing in the ostream itself as the argument.

Now you can do anything you want.
Johanus Dagius's Avatar
Newbie
 
Join Date: Jun 2007
Posts: 3
#3: Jun 23 '07

re: Need manipulator to set maximum I/O width


>>> Then write your own manipulator ...
OK, I understand your simple manipulator, which merely inserts and returns its own stuff into the output stream.

But I don't see how it can truncate output(s) further down the stream. I suspect this is not trivial thing to do. Would appreciate if someone could give me some pointers on how to do this (or even better: write the maxw(n) code for me :-)

I must say that I am surprised that something like maxw(n) is not part of "std"

Tnx,
Johanus
Moderator
 
Join Date: Mar 2007
Location: North Bend Washington USA
Posts: 5,375
#4: Jun 24 '07

re: Need manipulator to set maximum I/O width


I have a partial solution. The problem with a max manipulator is that it requires fiddling with the private data of ios_base. setw() calls ios_base::width(). You would have to derive from ios_base, or more likely, from basic_ostream to add these features.

I went another way.

What I did was go to the C/C++ Articles section and copied out the code for a simple Singleton object. This object contains the max field width. I added methods to set/get this value.

Next, I wrote an operator<<(ostream&, const string&). But this one is not in the std namespace so it is differentiable from std::operator<<(ostream&, const string&). Further, is occurs after the #include <iostream> so the compiler will prefer it to the one in std. My operator<< for string uses the singleton to determine how many characters of the string to display.

It's not a manipulator but it does get your desired output.

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class SysParms
  5. {   
  6.    private:
  7.         streamsize maxwidth;
  8.         SysParms(const SysParms&);  //Prevents making a copy
  9.  
  10.    protected:
  11.         SysParms();       //Only a SysParms member can call this
  12.                      //Prevents a user from creating singleton objects
  13.         virtual ~SysParms();  //Prevents just anyone from deleting the singleton
  14.  
  15.    public:
  16.  
  17.  
  18.        //The "official" access point.
  19.        static SysParms* Instance();
  20.        void MaxWidth(streamsize arg);
  21.        streamsize GetMaxWidth();
  22.  
  23. };
  24.  
  25.  
  26. namespace
  27. {
  28.     SysParms* instance = 0;        //Address of the singleton
  29.  
  30. }
  31.  
  32. SysParms::SysParms()
  33. {
  34.  
  35. }
  36. SysParms::~SysParms()
  37. {
  38.     delete instance;
  39.               instance = 0;
  40. }
  41.  
  42. //The "official" access point
  43. SysParms* SysParms::Instance()
  44. {
  45.    //"Lazy" initialization. Singleton not created until it's needed
  46.    if (!instance)
  47.    {
  48.       instance = new SysParms;
  49.    }
  50.    return instance;
  51. }
  52. void SysParms::MaxWidth(std::streamsize arg)
  53. {
  54.     this->maxwidth = arg;
  55. }
  56. streamsize SysParms::GetMaxWidth()
  57. {
  58.     return this->maxwidth;
  59. }    
  60.  
  61. ostream& operator<<(ostream& os, const string& str)
  62. {
  63.    streamsize max = SysParms::Instance()->GetMaxWidth();
  64.    streamsize length = str.size();
  65.  
  66.    for (int i = 0; (i < max) && ( i < length); ++i)
  67.    {
  68.       os << str[i];
  69.    }
  70.    return os;
  71. }
  72.  
  73. int main()
  74. {
  75.  
  76.     string str("abcdefghijklmnop");
  77.     SysParms::Instance()->MaxWidth(10);
  78.     cout <<  str << endl;
  79.     SysParms::Instance()->MaxWidth(5);
  80.     cout <<  str << endl;
  81.  
  82.     return 0;
  83. }
  84.  
  85.  
Johanus Dagius's Avatar
Newbie
 
Join Date: Jun 2007
Posts: 3
#5: Jun 27 '07

re: Need manipulator to set maximum I/O width


weaknessforcats wrote:
>>> The problem with a max manipulator is that it requires fiddling with the
>>> private data of ios_base. setw() calls ios_base::width(). You would have to
>>> derive from ios_base, or more likely, from basic_ostream to add these features ....

Hey, thanks for the partial solution. (It works!) I really appreciate your efforts here to help me, but I think I'll just use fprintf() in my C++ code to format my outputs. The fstream manipulators are just too clunky.

Thanks,
Johanus
Reply