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:
parent
034d5f99dc
commit
99c478768c
7 changed files with 109 additions and 33 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>() << "»";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
|
|
@ -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>>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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) + "»";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())+">";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue