4
\$\begingroup\$

This code can be found in the archive here. Usually I have a .cc file, but in this case it's all in a header. Am wondering about that. It needs to work in VS12. If possible I'll post more code from the archive for review. I started with this because it's used a lot. Tia.

#ifndef CMW_ErrorWords_hh
#define CMW_ErrorWords_hh

#include <exception>
#include <string>

namespace cmw {
class failure : public ::std::exception {
  ::std::string whatStr;

public:
  explicit failure (char const* what_) : whatStr(what_)
  {}

  explicit failure (::std::string what_) : whatStr(::std::move(what_))
  {}

  ~failure () throw()
  {}

  char const* what () const throw()
  { return whatStr.c_str(); }

  failure& operator<< (char* s)
  {
    whatStr.append(s);
    return *this;
  }

  failure& operator<< (char const* s)
  {
    whatStr.append(s);
    return *this;
  }

  failure& operator<< (::std::string const& s)
  {
    whatStr.append(s);
    return *this;
  }

  template <class T>
  failure& operator<< (T const& val)
  {
    whatStr.append(::std::to_string(val));
    return *this;
  }
};

class eof : public failure {

public:
  explicit eof (char const* what_) : failure(what_)
  {}

  ~eof () throw()
  {}

  template <class T>
  eof& operator<< (T val)
  {
    failure::operator<<(val);
    return *this;
  }
};

}
#endif

Edit - @Loki Astari

I have compile problems on both clang and gcc if I remove the non const version of that function. Clang says there's "no matching function for call to to_string."

whatStr.append(::std::to_string(val));

IIuc it goes on to say it doesn't like this line:

raise(failure("Blah blah  ") << yytext);

I ran across that a few months ago and found that adding the non-const version got the compilers to accept it. I'm not sure what the problem is really. I'm using flex and that's where yytext comes from.

Oo Tiib suggested the raise function as a help for debugging -- a central function where you could put a breakpoint to see the stack. It may be something used in some large projects. That made some sense so I decided to try it. I believe I need both versions of raise to avoid slicing.

Edit 2:

Removed raise functions from above code.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Is this code from your archive, or someone else's? \$\endgroup\$
    – Jamal
    Sep 17, 2013 at 2:56
  • \$\begingroup\$ @Jamal It's part of my archive. \$\endgroup\$
    – wood_brian
    Sep 17, 2013 at 3:21
  • \$\begingroup\$ Okay, just making sure. \$\endgroup\$
    – Jamal
    Sep 17, 2013 at 3:26
  • \$\begingroup\$ I think there's a typo for the std::to_string(). The :: in front of it shouldn't be there. \$\endgroup\$
    – Jamal
    Sep 17, 2013 at 20:37
  • 1
    \$\begingroup\$ If you inherit form std::exception then you can put the break point in std::exception::exception that's a nice central place to catch exceptions. \$\endgroup\$ Sep 17, 2013 at 22:09

1 Answer 1

4
\$\begingroup\$

Though std::exception does not have a constructor for taking an error message; the other standard excretions do. So you can make your exception class simpler by inheriting from one of these.

class failure : public ::std::runtime_error {

    public:
       failure (std::string const& msg) : ::std::runtime_error(msg)

I understand you are trying to make your exceptions easier to use by adding a couple of stream operator to the class. But you can achieve the same affect with greater flexibility using std::stringstream.

 // Your way:
 failure x("Hi there");
 x << ": More info:" << 5 << " At night:" << 22;

 // using string stream (works with all stream-able types)
 std::stringstream msg;
 msg << "Hi there" << ": More info:" << 5 << " At night:" << 22;
 failure y(msg.str());

If the only difference between a methods is the constness of their parameters. Then the const version is all you need. As it will accept normal values and promise not to change them.

// This method is not needed
failure& operator<< (char* s)
{
    whatStr.append(s);
    return *this;
}

// This method will handle both
// `char*` and `char const*` perfectly well.
// if you remove the first method above.
failure& operator<< (char const* s)
{
    whatStr.append(s);
    return *this;
}

I don't like your raise (and why two different version. Why not raise on the base class of std::exception (that will cover you for all exceptions)).

inline void raise (failure const& ex)

In my opinion (so its perfectly valid to believe differently) this buys you nothing and makes the code less readable.

raise(failure("hi"));

// Vs

throw failure("Hi");
\$\endgroup\$
1
  • \$\begingroup\$ I edited the original post. Am adding a comment here because I'm not sure you'll be notified otherwise. \$\endgroup\$
    – wood_brian
    Sep 17, 2013 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.