rethrow_if_nested()
is doubly unimplementableSection: 17.9.8 [except.nested] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2015-03-27 Last modified: 2017-07-30
Priority: 2
View all other issues in [except.nested].
View all issues with C++17 status.
Discussion:
rethrow_if_nested()
wants to determine "If the dynamic type of e
is publicly and unambiguously derived
from nested_exception
", but 7.6.1.7 [expr.dynamic.cast] specifies that dynamic_cast
has a couple
of limitations.
E
is int
, the dynamic type can't possibly derive from
nested_exception
. Implementers need to detect this and avoid dynamic_cast
, which would be ill-formed
due to 7.6.1.7 [expr.dynamic.cast]/2.) The Standardese is defective when E
is a nonpolymorphic class.
Consider the following example:
struct Nonpolymorphic { }; struct MostDerived : Nonpolymorphic, nested_exception { }; MostDerived md; const Nonpolymorphic& np = md; rethrow_if_nested(np);
According to 3.18 [defns.dynamic.type], the dynamic type of np
is MostDerived
. However, it's
physically impossible to discover this, and attempting to do so will lead to an ill-formed dynamic_cast
(7.6.1.7 [expr.dynamic.cast]/6). The Standardese must be changed to say that if E
is nonpolymorphic, nothing happens.
struct Nested1 : nested_exception { }; struct Nested2 : nested_exception { }; struct Ambiguous : Nested1, Nested2 { }; Ambiguous amb; const Nested1& n1 = amb; rethrow_if_nested(n1);
Here, the static type Nested1
is good (i.e. publicly and unambiguously derived from nested_exception
), but
the dynamic type Ambiguous
is bad. The Standardese currently says that we have to detect the dynamic badness, but
dynamic_cast
won't let us. 7.6.1.7 [expr.dynamic.cast]/3 and /5 are special cases (identity-casting and upcasting,
respectively) that activate before the "run-time check" behavior that we want (/6 and below). Statically good inputs succeed
(regardless of the dynamic type) and statically bad inputs are ill-formed (implementers must use type traits to avoid this).
dynamic_cast
),
but implementers shouldn't be asked to do so much work for such an unimportant case. (This case is pathological because the
usual way of adding nested_exception
inheritance is throw_with_nested()
, which avoids creating bad inheritance.)
The Standardese should be changed to say that statically good inputs are considered good.
Finally, we want is_base_of
's "base class or same class" semantics. If the static type is nested_exception
,
we have to consider it good due to dynamic_cast
's identity-casting behavior. And if the dynamic type is
nested_exception
, it is definitely good.
[2015-05, Lenexa]
WB: so the is_polymorphic
trait must be used?
STL and JW: yes, that must be used to decide whether to try using dynamic_cast
or not.
JW: I'd already made this fix in our implementation
STL: the harder case also involves dynamic_cast
. should not try using dynamic_cast
if we can
statically detect it is OK, doing the dynamic_cast
might fail.
STL: finally, want "is the same or derived from" behaviour of is_base_of
WB: should there be an "else no effect" at the end? We have "Otherwise, if ..." and nothing saying what if the condition is false.
TP I agree.
MC: move to Ready and bring to motion on Friday
7 in favor, none opposed
Proposed resolution:
This wording is relative to N4296.
Change 17.9.8 [except.nested] as depicted:
template <class E> void rethrow_if_nested(const E& e);-9- Effects: If
E
is not a polymorphic class type, there is no effect. Otherwise, if the static type or the dynamic type ofe
isnested_exception
or is publicly and unambiguously derived fromnested_exception
, callsdynamic_cast<const nested_exception&>(e).rethrow_nested()
.