Tip: String Wrapper for Formatted String Output in C++

String Wrapper for Formatted String Output in C++

For a long time, I was very reluctant to use "ostrstream," the C++ equivalent of the "sprintf" C function, because of longer and less understandable code:

ostrstream ss;
ss << "value = " << x;
string s = ss.str();

Using three lines and introducing another (besides string) class seems to me too much and inconsistent with my favorite principle of Occam's razor.

But relatively recently, I learned (by reading others' code) that sometimes this extra complexity can be hidden by using macros. For example, a log output macro could be defined in this manner:

#define LOG(arg) { ostringstrean ss; ss << arg;
   output(ss.str()); }

And can be used this way:

LOG("sample");
LOG("value = " << x);

So, I decided to try to implement something similar for just string formatting, without forcing the programmer to use any extra classes or variables, something like this:

String s;
s << "value = " << x;
// then using s for whatever is needed...

Here is the solution: a wrapper around the standard string and ostringstream classes:

//===============================================================
class String : public std::string
{
public:
   // Constructors
   String() {}
   String(const char * s_) : std::string(s_) {}
   String(std::string const & s_) : std::string(s_) {}
   String(const char * s_, int n_) : std::string(s_, n_) {}
   String(const char * s_, int p_, int n_) :
      std::string(s_, p_, n_) {}

   // Converting string to character pointer. Defining this
   // operator creates some danger of bugs caused by dangling
   // pointers, but is very convenient for passing string
   // parameters to "const char *" formal arguments
   operator const char *() { return c_str(); }

   char const & operator [](unsigned long int i_)
        const { return (*(std::string *)this)[i_]; }
   char const & operator [](unsigned int i_)
        const { return (*(std::string *)this)[i_]; }
   char const & operator [](int i_)
        const { return (*(std::string *)this)[i_]; }
   char & operator [](unsigned long int i_)
      { return (*(std::string *)this)[i_]; }
   char & operator [](unsigned int i_)
      { return (*(std::string *)this)[i_]; }
   char & operator [](int i_)
      { return (*(std::string *)this)[i_]; }

   String ToUpper() { String r = *this; for(unsigned int i = 0;
      i < size(); i++) r[i] = ::toupper(r[i]); return r; }
   String ToLower() { String r = *this; for(unsigned int i = 0;
      i < size(); i++) r[i] = ::tolower(r[i]); return r; }
};

template<typename T_> String operator *(String const & s_,
   T_ const & t_)
{
   return s_ + t_;
}

//===============================================================
class StringStream
{
public:

   struct StringStreamRef
   {
      explicit StringStreamRef(StringStream * ss_)
         throw() : ss(ss_) {}
      operator StringStream &() const throw()
      {
         return *ss;
      }
      StringStream * ss;
   };

   explicit StringStream(String & str_) : str(&str_)
   {
      ss = new std::ostringstream;
      *ss << *str;
   }
   explicit StringStream(StringStream & ss_) throw()
   {
      *this = ss_;
   }
   StringStream(StringStreamRef ssr_) throw()
   {
      *this = *ssr_.ss;
   }
   StringStream & operator =(StringStream & ss_) throw()
   {
      ss      = ss_.ss;
      str     = ss_.str;
      ss_.ss  = 0;
      ss_.str = 0;
      return *this;
   }
   ~StringStream()
   {
      if(ss && str)
      *str = ss->str();
      delete ss;
   }

   // Operators for converting last calculated string value to
   // String in case "<<" expression is in rhs.
   operator String() { return ss->str(); }
   template<typename T_> friend StringStream operator
      <<(StringStream ss_, T_ const & p_);
   template<typename T_> friend StringStream operator
      <<(String & s_, T_ const & p_);

   operator StringStreamRef() throw()
   {
      return StringStreamRef(this);
   }

private:
   std::ostringstream * ss;
   String * str;

};

template<typename T_> StringStream operator
   <<(StringStream ss_, T_ const & p_)
{
   *ss_.ss << p_;
   return ss_;
}

template<typename T_> StringStream operator
   <<(String & s_, T_ const & p_)
{
   StringStream w(s_);
   (*w.ss) << p_;
   return w;
}


Comments

  • Fake Oakley Big Taco low price for sale

    Posted by ppzcgwdaj on 06/27/2013 03:15pm

    Oakley Clearance ,The look on the Oakley sunglasses inject tone cool like the style, functionality and security caused by a variety of special features. Generally speaking, the content of Oakley sunglasses, feather weight and impact protection features. When I find out how they can resist direct sunlight, I could not help smiling to find out all of the momentum on the noble face of fashion Oakley sunglasses. fake ray ban sunglasses ,Oakley sunglasses defensive glasses varieties employ a the CLOS tendency to avoid a person's eye from the surrounding area, prevent stamping eye particles, water, or substance. The unique design and precision manufacturing touch, through the brand, to ensure each pair of sunglasses masterpiece. They will agree in a style, design and magnificence. CheAp OAkley DiSpAtch II ,Replacement lenses is unique from the normal lens, retain the inherent bending of sunshine to produce objects appear distorted and also the shift. The sunglasses might be separated into several types, points in accordance with the functional use. Ordinary sunglasses, decorative sunglasses, driver sunglasses etc. In this way, we always adhere to the path of development and innovation, creative features, stylish perfect science and technology together. There exists a health-related purposes Oakley sunglasses protect you because ultraviolet illumination skin ringworm individuals through the PUVA remedial ultraviolet radiation source is incredible for a long period. In fact, all on the Oakley sunglasses provide 100% UVA and UVB protection. Even non-colored fashion Oakley sunglasses supply the same UVA and UVB protection. In addition to the design of very fast and quality of the development of high-protection framework. Oakley sun glasses quality (specially the surround variety) provide quite the PV UV protect your eyes, there're suitable for both children and adults. Oakley have been perfecting the lens structure from the open frontier, thereby preventing the full visual field field on the down frame RIM like running and cycling athletes. From overmuch eye-catching glasses, the face area of history couple of years, style and color . runway in Europe or in the adjacent office cubicle, it's clear, glasses are becoming an indispensable chic accessories. There are several of those sunglasses, and also a number of different cheap OAKLEY sunglasses, various improvements. They may be about equally well. Choose the ideal brand can be sure of high quality and solid guarantee scheme, cannot simply mention how much interest and welcome jealous eyes.

    Reply
  • several issues

    Posted by cilu on 08/08/2008 03:23am

    There is an error in your code. This line cannot be fine. Can you please fix it? LOG("value = " << x; On the other hand, STL containers are not meant to be inherited. They all lack a virtual destructor, which can lead to 'slicing' problems.

    • Answer on

      Posted by MichaelFurman on 08/09/2008 05:27pm

      Hi, Marius. I see only one typo in the article that is outside the class code. More details on your comments: 1. - It is obviously a typo in the article, but not in presented code. 2. about meaning or not meaning - I refrain from comment - IMO these categories are not quite technical. 3. Need for virtual destructor is very questionable because the String class does not add any data members and does not override any member functions or introduce a new one. So I believe tat virtual destruction is not requested here. Though, I did not research C++ standard carefully for this matter - so, if you think that I am wrong, please elaborate a little. Thanks for your comments, regards, Michael

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today make data protection a must-have, as we live in a data driven society. The digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join eVault Chief Technology …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds