From 0f37cbdf8f3a3fc0e3a7c4d7a60c298ba77ded7f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 20 Apr 2015 04:11:55 +0200 Subject: [PATCH] un-burry an unit test draft from 2008 (for lib::AccessCasted) (extracted from the git history of file try.cpp, May 2008) basically this is the draft implementation from which AccessCasted was extracted. I see two problems - this version prints from within the access functions - we do not want the automatic static downcast anymore. meanwhile, I consider this kind of "do everything for me" programming style as dangerous. If unchecked donwcasts are desired, then code them up explicitly --- tests/library/meta/access-casted-test.cpp | 276 ++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 tests/library/meta/access-casted-test.cpp diff --git a/tests/library/meta/access-casted-test.cpp b/tests/library/meta/access-casted-test.cpp new file mode 100644 index 000000000..26dca382d --- /dev/null +++ b/tests/library/meta/access-casted-test.cpp @@ -0,0 +1,276 @@ +/* + AccessCasted(Test) - verify helper to cast or convert as appropriate + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + + +#include "lib/test/run.hpp" + +#include +#include +#include +#include +#include +#include + + +using std::string; +using std::cout; +using std::ostream; + +using boost::remove_pointer; +using boost::remove_reference; +using boost::is_convertible; +using boost::is_polymorphic; +using boost::is_base_of; +using boost::enable_if; + + +namespace lib { +namespace meta { +namespace test { + + + + template + struct can_cast : boost::false_type {}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + + template + struct has_RTTI + { + typedef typename remove_pointer< + typename remove_reference::type>::type TPlain; + + enum { value = is_polymorphic::value }; + }; + + template + struct use_dynamic_downcast + { + enum { value = can_cast::value + && has_RTTI::value + && has_RTTI::value + }; + }; + + template + struct use_static_downcast + { + enum { value = can_cast::value + && ( !has_RTTI::value + || !has_RTTI::value + ) + }; + }; + + template + struct use_conversion + { + enum { value = is_convertible::value + && !( use_static_downcast::value + ||use_dynamic_downcast::value + ) + }; + }; + + + template + struct EmptyVal + { + static X create() + { + cout << " NULL() " << __PRETTY_FUNCTION__ <<"\n"; + return X(); + } + }; + template + struct EmptyVal + { + static X*& create() + { + cout << " NULL & " << __PRETTY_FUNCTION__ <<"\n"; + static X* null(0); + return null; + } + }; + + + template + struct NullAccessor + { + typedef RET Ret; + + static RET access (...) { return ifEmpty(); } + static RET ifEmpty () { return EmptyVal::create(); } + }; + + template + struct AccessCasted : NullAccessor + { + using NullAccessor::access; + + template + static typename enable_if< use_dynamic_downcast, TAR>::type + access (ELM& elem) + { + cout << " dynamic " << __PRETTY_FUNCTION__ <<"\n"; + return dynamic_cast (elem); + } + + template + static typename enable_if< use_static_downcast, TAR>::type + access (ELM& elem) + { + cout << " static " << __PRETTY_FUNCTION__ <<"\n"; + return static_cast (elem); + } + + template + static typename enable_if< use_conversion, TAR>::type + access (ELM& elem) + { + cout << " convert " << __PRETTY_FUNCTION__ <<"\n"; + return elem; + } + + }; + + + + namespace { // Test fixture... + + struct B {}; + struct D : B {}; + + struct E : D + { + virtual ~E() {}; + }; + struct F : E {}; + + + ostream& operator<< (ostream& s, const B& b) { return s << "B{} adr="<<&b; } + ostream& operator<< (ostream& s, const D& d) { return s << "D{} adr="<<&d; } + ostream& operator<< (ostream& s, const E& e) { return s << "E{} adr="<<&e; } + ostream& operator<< (ostream& s, const F& f) { return s << "F{} adr="<<&f; } + + }//(End)Test fixture + + + + + + + /*************************************************************************************************//** + * @test verify a helper template for accessing values either through conversion or (dynamic) downcast. + * Typically, this helper is used in value holder containers or variant-like data structures, + * where the actual type is given at instantiation time of the template and possibly erased. + */ + class AccessCasted_test : public Test + { + virtual void + run (Arg) + { + + D d; + D* pD =&d; + B* pB =pD; + D& rD = *pD; + B& rB = *pB; + + D*& rpD = pD; + B*& rpB = pB; + + F f; + E& rE = f; + E* pE = &f; + D* pDE = pE; + + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + + + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_conversion = " << use_conversion::value << "\n"; + + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + + + cout << "Access(D as D&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as D&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as D&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as D*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as D*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as D*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as D*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as B&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as B&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as B&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as B*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as B*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as B*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as B*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as E&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(E& as F&) --->" << AccessCasted::access(rE) << "\n"; + cout << "Access(D(E)* as E*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(D(E)* as F*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(E* as F*) --->" << AccessCasted::access(pE) << "\n"; + } + }; + + + /** Register this test class... */ + LAUNCHER (AccessCasted_test, "unit common"); + + + +}}} // namespace lib::meta::test