diff --git a/research/try.cpp b/research/try.cpp index 510973c52..252532b1c 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -34,46 +34,61 @@ /** @file try.cpp ** How to build generic string conversion into `ostream::operator<< `. + ** + ** This task is actually a conglomerate of several chores: + ** - sanitise and segregate the type-traits usage + ** - disentangle the existing toString conversion helper + ** - extract a basic form from this helper, which can be placed + ** into a header with minimal dependencies. After some consideration, + ** I decided to allow `` in this category, which allows us + ** at least to show a type name as fallback + ** - distill an essential version of `enable_if`, which can be inlined. + ** This allows us to get rid of `boost::enable_if` finally. + ** - build a sensible `operator string()` for our `lib::P` based on this + ** - and _finally_, to come up with a templated version of the `ostream` + ** inserter `operator<<`, which does not cause too much havoc when + ** used by default. The greatest challenge here is to avoid ambiguous + ** overloads, yet also to deal with references, `void` and arrays. ** + ** \par policy + ** What shall be expected from such a generic toString conversion? + ** It should be _minimal_, it should be _transparent_ and it should + ** always work and deliver a string, irrespective of the circumstances. + ** By extension, this means that we do not want to differentiate much + ** between values, references and pointers, which also means, we do + ** not want to indicate pointers explicitly (just signal NULL, when + ** encountered). The situation is slightly different for the `ostream` + ** inserter; in a moder GUI application, there isn't much use for + ** STDOUT and STDERR, beyond error messages and unit testing. + ** Thus, we can strive at building a more convenient flavour + ** here, which does indeed even shows the address of pointers. + ** */ typedef unsigned int uint; #include "lib/p.hpp" -//#include "lib/format-util.hpp" #include "lib/diff/gen-node.hpp" -//#include "lib/util.hpp" #include "lib/meta/util.hpp" #include "lib/meta/trait.hpp" #include -//#include #include #include #include -//#include using lib::diff::GenNode; using lib::P; using lib::meta::can_convertToString; -//using util::unConst; using std::string; using std::cout; using std::endl; -class Reticent - { - uint neigh_ = 42; - }; -template -inline P -newP (ARGS&&... ctorArgs) -{ - return P{new X {std::forward(ctorArgs)...}}; -} + + /////////////////////////////////////////planned for meta/util.hpp template @@ -107,8 +122,10 @@ newP (ARGS&&... ctorArgs) inline string typeStr (TY const& ref) { return typeStr(&ref); } +///////////////////////////////copied from format-util.hpp +///////////////////////////////planned minimal conversion, maybe in meta/util.hpp ? template struct CustomStringConv { @@ -121,18 +138,18 @@ newP (ARGS&&... ctorArgs) static string invoke (X const& val) try { return string(val); } - catch(...) { return ""; } + catch(...) { return "↯"; } }; - -///////////////////////////////copied from format-util.hpp +///////////////////////////////planned minimal conversion, maybe in meta/util.hpp ? +///////////////////////////////shall go into the implementation of lib::P template inline string stringz (P ptr) { if (not ptr) - return "P"+typeStr(ptr.get())+"{ null }"; + return "⟂ P"+typeStr(ptr.get()); else return CustomStringConv::invoke (*ptr); } @@ -149,8 +166,8 @@ stringz (P ptr) template struct is_basically - : std::is_same ::TypePlain - ,typename Strip::TypePlain> + : std::is_same ::TypeReferred + ,typename Strip::TypeReferred> { }; template @@ -161,79 +178,132 @@ stringz (P ptr) > { }; } + +namespace lib { +namespace meta { + template<> + struct Unwrap + { + typedef void Type; + }; +}} /////////////////////////////////////////reworked traits - - - + + + /////////////////////////////////////////planned new ostream inclusion namespace { template - struct use_StringConversion - { - enum { value = can_convertToString::value - && !can_lexical2string::value - }; - }; - - template - struct use_ObjectTypeIndicator - : __and_<__not_> + struct use_StringConversion4Stream + : __and_< std::is_class::TypePlain> + ,__not_> ,__not_> - ,std::is_object > { }; } - template>> + template>> std::ostream& operator<< (std::ostream& os, X const& obj) { return os << CustomStringConv::invoke (obj); } -// -// template>> -// std::ostream& -// operator<< (std::ostream& os, X const& obj) -// { -// return os << CustomStringConv::invoke (obj); -// } - + + template>> + std::ostream& + operator<< (std::ostream& os, X* ptr) + { + if (ptr) + return os << (void*)ptr << " ↗" << *ptr; + else + return os << "⟂ " << typeStr(); + } + template std::ostream& operator<< (std::ostream& os, P const& ptr) { return os << stringz (ptr); } - + /////////////////////////////////////////planned new ostream inclusion + +class Reticent + { + uint neigh_ = 42; + }; + + +template +inline P +newP (ARGS&&... ctorArgs) +{ + return P{new X {std::forward(ctorArgs)...}}; +} + + + +template +using BasicallyString = is_basically; +template +using BasicallyChar = is_basically::type, char>; + + +void +showTypes() + { + +#define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (_EXPR_::value? "Yes":"No") << endl; +#define ANALYSE(_TYPE_) \ + cout << "Type: " STRINGIFY(_TYPE_) " ......"<); \ + SHOW_CHECK (BasicallyString<_TYPE_>); \ + SHOW_CHECK (std::is_arithmetic<_TYPE_>);\ + SHOW_CHECK (can_lexical2string<_TYPE_>); \ + SHOW_CHECK (can_convertToString<_TYPE_>); \ + SHOW_CHECK (use_StringConversion4Stream<_TYPE_>); + + + using CharLit = typeof("bla"); + using CharPtr = typeof(const char*); + using GenNodePtr = typeof(GenNode*); + using GenNodeRef = typeof(GenNode&); + + ANALYSE (string); + ANALYSE (CharLit); + ANALYSE (CharPtr) + ANALYSE (Reticent) + ANALYSE (P) + ANALYSE (GenNode) + ANALYSE (GenNodePtr) + ANALYSE (GenNodeRef) + ANALYSE (P) + cout << endl; + } + + + int main (int, char**) { + showTypes(); + auto psss = newP(); auto gnng = newP("Hui", "Buh"); -#define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (_EXPR_::value? "Yes":"No") << endl; - - using CharLit = typeof("bla"); - - using BasicallyString = is_basically; - using BasicallyChar = is_basically::type, char>; - - SHOW_CHECK (BasicallyChar); - SHOW_CHECK (BasicallyString); - SHOW_CHECK (std::is_arithmetic); - SHOW_CHECK (can_lexical2string); - SHOW_CHECK (can_convertToString); - SHOW_CHECK (use_StringConversion); - cout << "mauu..." << psss < #include namespace lumiera {