Symbol-agnostic cast using only type_info.
Before anyone mentions "boost::any", I am already fully aware of what it
can and cannot do.
I want what might be called "dynamic_any_cast", or a cast operation
that doesn't require the casting site to know anything about a base type.
That, or some way to automate parallel inheritance with simple wrapper
templates (e.g. If B : A, then wrapper<B> : wrapper<A> -- surprise bloat,
anyone?).
CODE (assuming only polymorphic types for now):
struct wrapper_base
{
// Returns a direct pointer to the object, or null if
// the cast failed.
//
// The calling code knows about the target type,
// and can just reinterpret_cast<> the result.
//
virtual void *do_direct_cast(const type_info &ti) noexcept = 0;
};
template<typename inner_t>
struct wrapper : wrapper_base
{
inner_t inner;
// 'inner_t' is hidden behind a wrapper_base,
// so there isn't any way (aside from "template virtuals"),
// to communicate type information aside
// from an ordinary type_info reference.
//
void *do_direct_cast(const type_info &ti) noexcept override
{
// returns a void * equivalent to
// reinterpret_cast<void*>(&target)
// on the target type, or null if not
// possible.
//
return direct_cast(addressof(this->inner), ti);
}
};
Basically, direct_cast would be a form of dynamic_cast that does not
require a static type symbol, but instead uses the symbol-agnostic type_info.
This allows type information to cross erasure boundaries.
Requiring knowledge of a base type at casting sites (e.g. as with
boost::any) creates a coupling with the type hierarchy in which the
cast is occurring, making the design of template code based on this
difficult if not impossible (every template will need to 'know' about
the base type involved somehow, leading to a proliferation of additional
symbols that might not be any of the implementation's concern).
I propose a casting operator, by any convenient name, that does
precisely this:
template<typename source_t>
[const] void *direct_cast(
[const] source_t *from_ptr,
const type_info &to
) noexcept;
This is possible, at least with the CRT shipped with VS2013 (basically,
just a wrapper around __RTDynamicCast). However, standardized facilities
are infinitely preferable to the mess required to make this portable.
Other possibilities include a variadic best-fit or first-fit symbol-agnostic
cast list this, such that the behavior can be made identical to the type
matching rules used for exception handling (without the need for slow,
runtime-induced context switches just to implement a type mapping):
// Returns effectively:
// {direct_cast(from_ptr, to_bfr[index]), index}
//
// or {nullptr, -1} if nothing fit.
//
template<typename source_t>
pair<[const] void *, int> first_fit_cast(
[const] source_t *from_ptr,
const type_info **to_bfr,
size_t to_count
) noexcept;
If to_bfr is in weak genealogical order, from most derived to least,
I believe this becomes a best-fit cast.
I make no claims of innovation or originality, as this covers a very
long-standing issue, is fairly easy to implement, and has been "solved"
partly here and there by various 3rd party tools, etc...
Thoughtful criticism is welcome and desired.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]