Apache C++ Standard Library User's Guide

## 32.6 Patterns for Extractors and Inserters of User-Defined Types

Here is the pattern for an extractor:

    template<class charT, class Traits>
    std::basic_istream<charT, Traits>&
    operator>> (std::basic_istream<charT,
                Traits>& is, UserDefinedType& x)
    {
      std::ios_base::iostate err = 0;

      // Create a sentry object (may set error bits or throw failure)
      typename basic_istream<charT, Traits>::sentry ipfx(is);

      try {

        // Proceed with I/O only if sentry is okay.

        if(ipfx) {
          // Typically you access the stream's locale or buffer.
          // Don't call other stream I/O functions.

          // Add state bits to the err variable if necessary,
          // for example:
          // if (...)
          //    err |= std::ios_base::failbit;
        }
      }
      catch(...) {
        bool flag = false;
        try {
          // set failbit (may throw failure)
          is.setstate(std::ios_base::failbit);
        }
        catch(...) { flag = true; }

        // Re-throw original exception (thrown from facet or buffer)
        if (flag)
          throw;
      }

      // As the last step, set error bits (may throw failure)
      if (err)
        is.setstate(err);

      return is;
    }

Similarly, the pattern for the inserter looks like this:

    template<class charT, class Traits>
    std::basic_ostream<charT, Traits>&
    operator<<(std::basic_ostream<charT, Traits >& os,
                const UserDefinedType& x)
    {
      std::ios_base::iostate err = 0;

      // Create a sentry object (may set error bits or throw failure)
      typename basic_ostream<charT, Traits>::sentry opfx(os);

      try {
        // Proceed with I/O only if sentry is okay
        if (opfx) {
          // Typically you access the stream's locale or buffer.
          // Don't call other stream I/O functions

          // Add state bits to the err variable if necessary,
          // for example:
          // if (...)
          //    err |= std::ios_base::failbit;

          // Reset the field width after usage, that is,
          // os.width(0);
        }
      } //try
      catch(...) {
        bool flag = false;
        try {
          // set failbit (may throw failure)
          os.setstate(std::ios_base::failbit);
        }
        catch(...) {
          // Catch exception, do not rethrow
          flag = true;
        }
        // Rethrow original exception (from facet or buffer)
        if (flag)
           throw;
      }

      // As the last step, set error bits (may throw failure)
      if (err)
        os.setstate(err);

      return os;
    }