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:
parent
334f542897
commit
6633cb03bd
2 changed files with 14 additions and 5 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue