sanity: how to pass 'anything' properly to the type diagnostics function

turns out this is a tricky situation.
We want to accept pretty mutch everything, yet we want to get a grip
on anything object-like, so to reveal available RTTI information.
Now, given the way C++ template substitution works, the 'TY const&' overload
wins with only a few exceptions. The reason is, C++ invokes most functions
passing the concrete argument as reference, unless this is not possible,
because the concrete artument is a rvalue. The automatic reduction of
reference expressions does the rest. Consequently the overload with 'const&'
turns out to be the best match even when we invoke the function with a
pointer expression, which would then be made into a pointer-to-a pointer
by our forward call.

There are two remedies for this dilemma:
- make the second overload just typeStr (TY&)
- explicitly remove the second overload for pointers

The first solution unfortunately would rule out passing of anonymous
objects like concatenated strings; in fact it would rule out passing
rvalues as such. While the second solution, chosen here, works really
for everything, and also has the nice side effect of stripping away
any const, pointer and reference adornements elegantly before we
even start to analyse the type.

The only downside of this solution is that it looks intimidating
to the casual reader. Well, I'd say, get used to it.
This commit is contained in:
Fischlurch 2016-01-09 01:32:02 +01:00
parent 334f542897
commit 6633cb03bd
2 changed files with 14 additions and 5 deletions

View file

@ -225,6 +225,12 @@ namespace meta {
* and further simplify the type string, leaving out some common
* (hard wired) namespace prefixes, and stripping typical adornments
* like `const`, `*` and `&`
* @remarks almost all calls will enter through the `const&` variant of this
* function, since C++ considers this best match in template substitution.
* Thus, we deliberately force calls with pointer to enter here, since we
* do want the pointer itself (and not a pointer to the pointer). We then
* pass the "object" as so called "glvalue" to the `typeid()` function,
* so to get the evaluation of RTTI, when applicable.
* @warning this function does string transformations behind the scenes,
* and thus should not be used in performance critical context. Moreover,
* the returned type string is not necessarily exact and re-parsable.
@ -241,7 +247,8 @@ namespace meta {
{ return FAILURE_INDICATOR; }
template<typename TY>
inline std::string
inline disable_if<std::is_pointer<TY>,
std::string >
typeStr (TY const& ref) noexcept
{
return typeStr (&ref);
@ -270,7 +277,8 @@ namespace meta {
}
template<typename TY>
inline std::string
inline disable_if<std::is_pointer<TY>,
std::string >
typeSymbol (TY const& ref)
{
return typeSymbol (&ref);
@ -331,7 +339,7 @@ namespace util {
template<typename X>
inline std::string
showAddr (X const& elm) noexcept
showAddr (X& elm) noexcept
{
return showAddr(&elm);
}

View file

@ -80,7 +80,8 @@ namespace test{
}
template<typename T>
inline string
inline meta::disable_if<std::is_pointer<T>,
string > // note:: force invocations with pointer to the first overload
showSizeof (T const& obj, const char* name=0)
{
return showSizeof (&obj, name);
@ -100,7 +101,7 @@ namespace test{
string
showRefKind()
{
return std::is_lvalue_reference<R>::value? "REF"
return std::is_lvalue_reference<R>::value? "REF"
: std::is_rvalue_reference<R>::value? "MOV"
: "VAL";
}