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.
First, nonpolymorphic inputs. These could be non-classes, or nonpolymorphic classes. The Standardese handles non-classes,
although implementers need special logic. (If 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.19 [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.
Second, statically good but dynamically bad inputs. Consider the following example:
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).
It might be possible to implement this with clever trickery involving virtual base classes, but implementers shouldn't be asked
to do that. It would definitely be possible to implement this with a compiler hook (a special version of 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()
.