2

I was wondering whether it would be possible (through clever conversion rules) to write an "exception" class that would help with the following:

Instead of writing:

try {
 ...
} catch (std::execption const e) {    // StdLib exceptions
} catch (CException* pEx) {           // MFC exceptions
} catch (CORBA::Exception const& e) { // CORBA exceptions
} // note handling code inside catch blocks omitted for brevity

It would be nice if a type could be constructed that would work like so:

try {
  ...
} catch( magic_exception_handle const& e) { // catches all three types mentioned above
  const std::string msg = e.what(); // could also provide generalized message extraction
}

Would this be possible? How?

Note: Other solutions I don't like:

  • I can do catch(...) but I do not want to catch-all.
  • catch-handler function:

    void handler3() {
      try {
        throw;
      } catch (std::execption const e) {    // StdLib exceptions
      } catch (CException* pEx) {           // MFC exceptions
      } catch (CORBA::Exception const& e) { // CORBA exceptions
      } // note handling code inside catch blocks omitted for brevity
    }
    
    ...
    try { ... } catch(...) { handler3(); }
    

    doesn't cut it either, because while any other exception would be thrown outwards, it first would catch any other exception which results in a premature stack unwinding before it is rethrown. (Which is very inconvenient for any resulting crash-dumps on Windows.)

  • I could write a Macro for the catch block. (ugh)

So, is it possible to create a magic_exception_handle type? Has it been done?

Martin Ba
  • 37,187
  • 33
  • 183
  • 337
  • can you have those 3 exceptions derive from a common base class (like `std::exception` eg. since you're already catching that) ? If so, you can catch that base class. – Sander De Dycker Apr 30 '13 at 14:24
  • Since [conversions are not considered when matching exception handlers](http://stackoverflow.com/a/2343294/20984), I don't think this can be done. – Luc Touraille Apr 30 '13 at 14:40
  • @SanderDeDycker: `CException*` is a pointer - even if I were insane enough to hack the MFC sources, I couldn't make it derive from anything. – Martin Ba Apr 30 '13 at 14:48
  • @LucTouraille: Thanks. I guess that answers the question. – Martin Ba Apr 30 '13 at 14:50
  • 1
    @MartinBa: a quick read of Standard 15.3.3 shows there's no non-hackish options. Re `CException*` not deriving from anything... off in hack land you could potentially catch it by `const void*` and recognise it by an initial pointer to RTTI CException's information, but that doesn't help as the other two types aren't pointers allowing similar discrimination. – Tony Delroy Apr 30 '13 at 15:07

1 Answers1

1

Your only real option is to invert the logic:

template<typename F, typename... Args>
auto convert_exceptions(F &&f, Args... &&args)
-> decltype(f(std::forward<Args>(args)...)) {
   try {
      return f(std::forward<Args>(args)...));
   } catch (std::exception const e) {    // StdLib exceptions
      std::throw_with_nested(magic_exception{...});
   } catch (CException* pEx) {           // MFC exceptions
      std::throw_with_nested(magic_exception{...});
   } catch (CORBA::Exception const& e) { // CORBA exceptions
      std::throw_with_nested(magic_exception{...});
   }
}

You can now write:

try {
   convert_exceptions([&]() {
      // ...
   });
} catch (const magic_exception &e) {
   // ...
}
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • **Ha!** Wrapping the code in a lambda + object that does the catching *instead* of writing a try-catch block isn't such bad idea. No need for the magic exception in your answer. I'd rename your `convert_exception` to `catch_exception` and provide the necessary handler code in it and then I have a reusable try-catch-block. -- Well, I would, if I'd had a C++11 compiler. But I have to remember this. :-) – Martin Ba Apr 30 '13 at 15:18