fix a problem with formatting arbitrary types; reneable the broken tests
This commit is contained in:
parent
151d17e4de
commit
1533e5bd0d
5 changed files with 72 additions and 5 deletions
|
|
@ -39,6 +39,7 @@
|
|||
#include <string>
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
namespace util {
|
||||
|
||||
using lumiera::typelist::can_ToString;
|
||||
using lumiera::typelist::can_lexical2string;
|
||||
using lumiera::Symbol;
|
||||
using boost::enable_if;
|
||||
using boost::disable_if;
|
||||
|
|
@ -70,11 +72,36 @@ namespace util {
|
|||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_indirect2string ( typename enable_if< can_lexical2string<X>,
|
||||
X >::type const& val)
|
||||
{
|
||||
try { return boost::lexical_cast<string> (val); }
|
||||
catch(...) { return ""; }
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
inline string
|
||||
invoke_indirect2string ( typename disable_if< can_lexical2string<X>,
|
||||
X >::type const&)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** try to get an object converted to string */
|
||||
/** try to get an object converted to string.
|
||||
* An custom/standard conversion to string is used,
|
||||
* if applicable; otherwise, some standard types can be
|
||||
* converted by a lexical_cast (based on operator<< ).
|
||||
* Otherwise, either the fallback string is used, or just
|
||||
* a string denoting the (mangled) type.
|
||||
*/
|
||||
template<typename TY>
|
||||
inline string
|
||||
str ( TY const& val
|
||||
|
|
@ -86,8 +113,17 @@ namespace util {
|
|||
return string(prefix) + invoke_2string<TY>(val);
|
||||
|
||||
else
|
||||
return fallback? fallback
|
||||
: tyStr(val);
|
||||
{
|
||||
if (can_lexical2string<TY>::value)
|
||||
{
|
||||
string res (invoke_indirect2string<TY> (val));
|
||||
if ("" != res)
|
||||
return string(prefix) + res;
|
||||
}
|
||||
|
||||
return fallback? fallback
|
||||
: tyStr(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,17 @@
|
|||
#include "lib/meta/util.hpp"
|
||||
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist {
|
||||
|
||||
using boost::enable_if;
|
||||
using boost::is_arithmetic;
|
||||
|
||||
|
||||
/** Trait template for detecting if a type can be converted to string.
|
||||
* For example, this allows to write specialisations with the help of
|
||||
|
|
@ -46,6 +52,24 @@ namespace typelist {
|
|||
};
|
||||
|
||||
|
||||
/** Trait template for guarding \c lexical_cast<..> expressions.
|
||||
* Such an expression won't even compile for some types, because of
|
||||
* missing or ambiguous output operator(s).
|
||||
* Ideally, there would be some automatic detection (relying on the
|
||||
* existence of an operator<< for the given type. But I couldn't make
|
||||
* this work, so I fell back on just declaring types which are known
|
||||
* to work with lexical_cast to string
|
||||
* @note this compile-time trait can't predict if such an conversion
|
||||
* to string will be successful at runtime; indeed it may throw,
|
||||
* so you should additionally guard the invocation with try-catch!
|
||||
*/
|
||||
template<typename X>
|
||||
struct can_lexical2string
|
||||
{
|
||||
enum { value = is_arithmetic<X>::value
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
}} // namespace lumiera::typelist
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -240,6 +240,9 @@ out: «..util.test.Reticent.»
|
|||
out: <no comment>
|
||||
out: ^hey Joe!
|
||||
out: ^he says: hey Joe!
|
||||
out: ^the truth: 0
|
||||
out: ^just a number: 1.234e\+56
|
||||
out: ^12345X
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ PLANNED "CommandBasic_test" CommandBasic_test <<END
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Argument & Memento handling" CommandArgument_test <<END
|
||||
TEST "Argument & Memento handling" CommandArgument_test <<END
|
||||
out: Command-State. arguments=unbound, ·noUNDO·.
|
||||
out: capture state...
|
||||
out: Command-State. arguments=Closure\(\), ·noUNDO·.
|
||||
|
|
@ -35,7 +35,7 @@ out: RESET...undoIt\(time=00:..:....00\)----memento-:START...doIt\( Time=00:..:.
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Command functor and UNDO functor" CommandMutation_test <<END
|
||||
TEST "Command functor and UNDO functor" CommandMutation_test <<END
|
||||
out: Mutation\(untied\)
|
||||
out: param values: Closure\(23\)
|
||||
out: Mutation\(Closure\(23\)\)
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ namespace test {
|
|||
|
||||
cout << str (chatterer) << endl;
|
||||
cout << str (chatterer, "he says: ", "<no comment>") << endl;
|
||||
|
||||
cout << str (false, "the truth: ") << endl;
|
||||
cout << str (12.34e55, "just a number: ") << endl;
|
||||
cout << str (short(12)) << str (345L) << str ('X') << endl;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue