Sliced On Exit

struct Base : std::exception {
    const char *what() const noexcept override { return "base"; }
};
struct Derived : Base {
    const char *what() const noexcept override { return "derived"; }
};

try { throw Derived{}; } catch (Base e)        { std::puts(e.what()); }
try { throw Derived{}; } catch (const Base &e) { std::puts(e.what()); }

What does this print?

A

base then base: a handler parameter is always initialized from a Base view of the exception object

B

derived then derived: what is virtual, so the dynamic type wins in both handlers

C

base then derived

D

Neither handler matches, because the thrown type is Derived and the handlers name Base; the program calls std::terminate