Can I write a catch clause similar to shorthand function templates?

At the top of my program, I have an exception handler.
It looks something like this:

try{ //majority of program } catch(...){ Handle_All_Exceptions(); } void Handle_All_Exceptions(){ try{throw;} catch(TypeA const& e){Handle(e) ;} catch(TypeB const& e){Handle(e) ;} catch(TypeC const& e){Handle(e) ;} catch(TypeD const& e){Handle(e) ;} catch(...) {Handle_Unknown();} } void Handle(TypeA const& e){ //... } void Handle(TypeB const& e){ //... } void Handle(TypeC const& e){ //... } void Handle(TypeD const& e){ //... } void Handle_Unknown(){ //... } 

As I get more more exception types,
I would like to use a more general approach.
How to apply generalized programming to the Handle_All_Exceptions function ?


Could there be something like this in newer versions of C ++?

 catch(auto e){Handle(e)}; catch(...){Handle_Unknown();} 
+5
source share
1 answer

It is impossible without significant changes in the language and its system of exceptions. Although catch-clause handlers and function parameters may look syntactically similar, they work in a completely different way. Consider:

 struct up {}; struct down { constexpr down(up) noexcept {} }; void func(down const&) {} void except() { try { throw up {}; } catch(down const&) {} } int main() { func(up {}); // fine except(); // exception `up` escapes } 

Coliru

In other words, the down const& parameter accepts everything that can be converted to down , while the down const& handler will be associated with exception objects of type down or a type that is uniquely derived from down .

The big difference here is that form-to-convert relationships can take many forms. In our example, we used the conversion constructor, but instead we could use the conversion operator inside up . Whereas "(publicly, explicitly) derived from" can only be accepted in one simple way, and in exactly one place throughout the program: wherever the derived type is defined. This is important when we consider separate compilation. Consider the following program:

 // a.cpp // defined in b.cpp void throws() noexcept(false); template<typename X> concept bool Fooable = requires(X x) { x.foo(); } int main() { try { throws(); // imaginary syntax for catching models of a concept } catch(Fooable const&) {} } // b.cpp // defined in c.cpp struct other; struct model { void foo() {} other* foo(int) { return nullptr; } void bar() {} }; void throws() noexcept(false) { throw model {}; } // c.cpp omitted 

When b.cpp compiled, the compiler does not know that a.cpp will ask the question: "Are you x.foo() this object capable of x.foo() ?". If he pessimistically fixes this fact in the same way (as well as in accordance with the current rules, the connection "comes from", if any, is recorded somewhere)? Should he also record the fact that model is capable of x.bar() , although he does not need a complete program? What if Fooable instead checked on x.foo(0)->baz() ? Where, when and how will it be written if other were defined so that the expression makes sense? Note that model and other defined separately, and each one does not know (much) about the other.

Of course, what you are asking for is not directly impossible, but I hope that we can agree that it looks very different in our system and will require a lot of effort before it works. In accordance with the current rules, general programming for exceptions can only go so far, using the old-fashioned class hierarchies - this is the path of least resistance.

0
source

All Articles