/* ACCESS-CASTED.hpp - util template to access a value using conversion or cast 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. */ /** @file access-casted.hpp ** Helper for accessing a value, employing either conversion or downcast, ** depending on the relation of the source type (type of the original value) ** and the target type (type we need within the usage context). ** When instantiating AcessCasted, we get a template static function ** \c AcessCasted::access(SRC& elm), but the actual implementation ** is chosen using boost::type_traits. If no sensible implementation can be ** selected, \c EmptyVal::create() is invoked instead, which by default ** creates a NULL value or similar by using the no-argument ctor of the ** type TAR. Alternatively, you may define an specialisation of EmptyVal, ** e.g. throwing an exception instead of creating a NULL value. ** ** @see lumiera::WrapperPtr usage example to access a variant record ** */ #ifndef UTIL_ACCESS_CASTED_H #define UTIL_ACCESS_CASTED_H #include #include #include #include #include #include namespace util { 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; 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() { return X(); } }; template struct EmptyVal { static X*& create() { static X* nullP(0); return nullP; } }; 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) { return dynamic_cast (elem); } template static typename enable_if< use_static_downcast, TAR >::type access (ELM& elem) { return static_cast (elem); } template static typename enable_if< use_conversion, TAR >::type access (ELM& elem) { return elem; } }; } // namespace util #endif