While it is good practice to throw only exceptions of types derived from std::exception
class, C++ makes it possible to throw anything. All below examples are valid C++:
throw "foo"; // throws an instance of const char* throw 5; // throws an instance of int struct {} anon; throw anon; // throws an instance of not-named structure throw []{}; // throws a lambda!
The last example is interesting, as it potentially allows passing some code to execute at catch site without having to define a separate class or function.
But is it at all possible to catch a lambda (or a closure)? catch ([]{} e)
does not work.
The most straightforward way would be to use a try-catch block, wrap the checked exception into an unchecked exception and rethrow it: List<Integer> integers = Arrays. asList(3, 9, 7, 0, 10, 20); integers. forEach(i -> { try { writeToFile(i); } catch (IOException e) { throw new RuntimeException(e); } });
A lambda expression cannot throw any checked exception until its corresponding functional interface declares a throws clause. An exception thrown by any lambda expression can be of the same type or sub-type of the exception declared in the throws clause of its functional interface.
A lambda expression body can't throw any exceptions that haven't specified in a functional interface. If the lambda expression can throw an exception then the "throws" clause of a functional interface must declare the same exception or one of its subtype.
Exception handlers are matched based on type, and the implicit conversions done to match an exception object to a handler are more limited than in other contexts.
Each lambda expression introduces a closure type that is unique to the surrounding scope. So your naive attempt cannot work, for []{}
has an entirely different type in the throw expression and the handler!
But you are correct. C++ allows you to throw any object. So if you explicitly convert the lambda before-hand to a type that matches an exception handler, it will allow you to call that arbitrary callable. For instance:
try { throw std::function<void()>{ []{} }; // Note the explicit conversion } catch(std::function<void()> const& f) { f(); }
This may have interesting utility, but I'd caution against throwing things not derived from std::exception
. A better option would probably be to create a type that derives from std::exception
and can hold a callable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With