From 6633cb03bde04918128802e8a16fdcef90524a41 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 9 Jan 2016 01:32:02 +0100 Subject: [PATCH] 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. --- src/lib/meta/util.hpp | 14 +++++++++++--- src/lib/test/test-helper.hpp | 5 +++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lib/meta/util.hpp b/src/lib/meta/util.hpp index 8bd135120..26e3997b1 100644 --- a/src/lib/meta/util.hpp +++ b/src/lib/meta/util.hpp @@ -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 - inline std::string + inline disable_if, + std::string > typeStr (TY const& ref) noexcept { return typeStr (&ref); @@ -270,7 +277,8 @@ namespace meta { } template - inline std::string + inline disable_if, + std::string > typeSymbol (TY const& ref) { return typeSymbol (&ref); @@ -331,7 +339,7 @@ namespace util { template inline std::string - showAddr (X const& elm) noexcept + showAddr (X& elm) noexcept { return showAddr(&elm); } diff --git a/src/lib/test/test-helper.hpp b/src/lib/test/test-helper.hpp index 483076019..953f96dc6 100644 --- a/src/lib/test/test-helper.hpp +++ b/src/lib/test/test-helper.hpp @@ -80,7 +80,8 @@ namespace test{ } template - inline string + inline meta::disable_if, + 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::value? "REF" + return std::is_lvalue_reference::value? "REF" : std::is_rvalue_reference::value? "MOV" : "VAL"; }