generic-toString(#985): define streamlined converter

...based on all the clean-up and reorganisation done thus far,
we're now able to rebuild the util::str in a more direct and
sane way, and thus to disentangle the header inclusion problem.
This commit is contained in:
Fischlurch 2016-01-08 01:00:05 +01:00
parent 034d5f99dc
commit 99c478768c
7 changed files with 109 additions and 33 deletions

View file

@ -86,7 +86,6 @@ using lib::meta::is_StringLike;
using lib::meta::can_lexical2string;
using lib::meta::can_convertToString;
using lib::meta::use_StringConversion4Stream;
using lib::meta::CustomStringConv;
using lib::meta::Strip;
using std::string;

View file

@ -39,7 +39,6 @@
#define LIB_FORMAT_COUT_H
#include "lib/format-obj.hpp"
//#include "lib/util.hpp"
#include <string>
#include <iostream>
@ -50,20 +49,6 @@ using std::cerr;
using std::endl;
namespace lib {
namespace meta {
/** when to use custom string conversions for output streams */
template<typename X>
struct use_StringConversion4Stream
: __and_<std::is_class<typename Strip<X>::TypePlain>
,__not_<std::is_pointer<X>>
,__not_<can_lexical2string<X>>
>
{ };
}}
namespace std {
@ -80,7 +65,7 @@ namespace std {
ostream&
operator<< (ostream& os, X const& obj)
{
return os << lib::meta::CustomStringConv<X>::invoke (obj);
return os << util::StringConv<X>::invoke (obj);
}
@ -93,7 +78,7 @@ namespace std {
operator<< (ostream& os, X const* ptr)
{
if (ptr)
return util::showAddr(os, ptr) << "" << lib::meta::CustomStringConv<X>::invoke (*ptr);
return util::showAddr(os, ptr) << "" << util::StringConv<X>::invoke (*ptr);
else
return os << "⟂ «" << lib::meta::typeStr<X>() << "»";
}

View file

@ -30,8 +30,8 @@
** tasks commonly used from debugging and diagnostics code, both to
** investigate object contents and show types and addresses. They
** are referred from our [lightweight string converter](\ref
** lib::meta::CustomStringConv), but also from the util::toString()
** function and more common [formatting utils](format-util.hpp).
** util::StringConv), but also from the util::toString() function
** and more common [formatting utils](format-util.hpp).
**
** @see FormatHelper_test
** @see FormatString_test

View file

@ -43,10 +43,9 @@
#define LIB_FORMAT_OBJ_H
#include "lib/meta/trait.hpp"
//#include "lib/util.hpp"
#include <string>
#include <boost/lexical_cast.hpp>
#include <string>
namespace std { // forward declaration to avoid including <iostream>
@ -83,6 +82,10 @@ namespace meta {
}}// namespace lib::meta
namespace util {
std::string showDouble (double) noexcept;
@ -93,6 +96,70 @@ namespace util {
std::ostream& showAddr (std::ostream&, void const* addr);
namespace {
/** toggle to prefer specialisation with direct lexical conversion */
template<typename X>
using enable_LexicalConversion = lib::meta::enable_if< lib::meta::use_LexicalConversion<X>>;
}
/* === generalise the failsafe string conversion === */
/** @note base case is defined in meta/util.hpp */
template<typename X>
struct StringConv<X, enable_LexicalConversion<X>>
{
static std::string
invoke (X const& val) noexcept
try { return boost::lexical_cast<std::string> (val); }
catch(...) { return ""; }
};
/** explicit specialisation to control precision of double values.
* @note we set an explicit precision, since this is a diagnostic facility
* and we typically do not want to see all digits, but, for test code,
* we do want a predictable string representation of simple fractional
* values like `0.1` (which can not be represented as binary floats)
*/
template<>
struct StringConv<double>
{
static std::string
invoke (double val) noexcept
{
return util::showDouble (val);
}
};
template<>
struct StringConv<float>
{
static std::string
invoke (float val) noexcept
{
return util::showFloat (val);
}
};
/**
* get some string representation of any object, reliably.
* A custom string conversion operator is invoked, if applicable,
* while all lexically convertible types (numbers etc) are treated
* by boost::lexical_cast. For double or float values, hard wired
* rounding to a fixed number of digits will be performed, to yield
* a predictable display of printed unit-test results.
*/
template<typename TY>
inline std::string
toString (TY const& val) noexcept
{
return StringConv<TY>::invoke (val);
}
} // namespace util
#endif /*LIB_FORMAT_OBJ_H*/

View file

@ -302,6 +302,22 @@ namespace meta {
>
{ };
template<typename X>
struct use_LexicalConversion
: __and_<can_lexical2string<X>
,__not_<can_convertToString<X>>
>
{ };
/** when to use custom string conversions for output streams */
template<typename X>
struct use_StringConversion4Stream
: __and_<std::is_class<typename Strip<X>::TypePlain>
,__not_<std::is_pointer<X>>
,__not_<can_lexical2string<X>>
>
{ };

View file

@ -114,10 +114,10 @@ namespace meta {
* Might fail in more tricky situations (references, const, volatile)
* @see \ref format-obj.hpp more elaborate solution including lexical_cast
*/
template<typename T>
template<typename X>
struct can_convertToString
{
static T & probe();
static X & probe();
static Yes_t check(std::string);
static No_t check(...);
@ -126,6 +126,11 @@ namespace meta {
static const bool value = (sizeof(Yes_t)==sizeof(check(probe())));
};
/** toggle for explicit specialisations */
template<typename X>
using enable_CustomStringConversion = enable_if<can_convertToString<X>>;
/** strip const from type: naive implementation */
template<typename T>
@ -220,6 +225,13 @@ namespace meta {
return typeStr (&ref);
}
}}// namespace lib::meta
namespace util {
using lib::meta::typeStr;
/** failsafe invocation of custom string conversion.
@ -234,7 +246,7 @@ namespace meta {
* the returned string indicates "" in this case.
*/
template<typename X, typename COND =void>
struct CustomStringConv
struct StringConv
{
static std::string
invoke (X const& x) noexcept
@ -243,7 +255,7 @@ namespace meta {
};
template<typename X>
struct CustomStringConv<X, enable_if<can_convertToString<X>> >
struct StringConv<X, lib::meta::enable_CustomStringConversion<X>>
{
static std::string
invoke (X const& val) noexcept
@ -254,11 +266,8 @@ namespace meta {
// NOTE: this is meant to be extensible;
// more specialisations are e.g. in format-obj.hpp
}}// namespace lib::meta
namespace util {
/** pretty-print a double in fixed-point format */
std::string showDouble (double) noexcept;
@ -280,7 +289,7 @@ namespace util {
inline std::string
showPtr (X* ptr =nullptr)
{
return ptr? showAddr(ptr) + "" + lib::meta::CustomStringConv<X>::invoke(*ptr)
return ptr? showAddr(ptr) + "" + StringConv<X>::invoke(*ptr)
: "⟂ «" + typeStr(ptr) + "»";
}

View file

@ -158,7 +158,7 @@ namespace lib {
P<TAR,BASE>::operator std::string() const noexcept
try {
if (BASE::get())
return meta::CustomStringConv<TAR>::invoke (this->operator*());
return util::StringConv<TAR>::invoke (this->operator*());
else
return "⟂ P<"+meta::typeStr(this->get())+">";
}