/* 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. ** ** @todo WIP 4/2015 is being rewritten ///////////////////////////////////////////TICKET #738 needs slight overhaul and clean-up ** @see lumiera::WrapperPtr usage example to access a variant record ** @see lib::InPlaceAnyHolder usage example to access a subclass in embedded storage ** */ #ifndef UTIL_ACCESS_CASTED_H #define UTIL_ACCESS_CASTED_H #include "lib/error.hpp" #include #include namespace util { using std::remove_pointer; using std::remove_reference; namespace error = lumiera::error; template using PlainType = typename remove_pointer< typename remove_reference::type>::type; template struct has_RTTI { static constexpr bool value = std::is_polymorphic>::value; }; template struct can_downcast { static constexpr bool value = std::is_base_of, PlainType>::value; }; template struct can_use_dynamic_downcast { static constexpr bool value = !std::is_convertible::value && can_downcast::value && has_RTTI::value; }; template struct can_use_conversion : std::is_convertible { }; template struct can_take_address { static constexpr bool value = !std::is_pointer::type>::value && std::is_pointer::type>::value; }; template struct can_dereference { static constexpr bool value = !std::is_pointer::type>::value && std::is_pointer::type>::value; }; template struct if_can_use_dynamic_downcast : std::enable_if< can_use_dynamic_downcast::value, TAR> { }; template struct if_can_use_conversion : std::enable_if< can_use_conversion::value, TAR> { }; template struct if_can_take_address : std::enable_if< can_take_address::value, TAR> { }; template struct if_can_dereference : std::enable_if< can_dereference::value, TAR> { }; template struct AccessCasted { typedef TAR Ret; template static typename if_can_use_dynamic_downcast::type access (SRC&& elem) { std::cerr << "downcast-"<()<<" && ->"<()< (std::forward(elem)); } template static typename if_can_use_conversion::type access (SRC&& elem) { std::cerr << "convert-"<()<<" && ->"<()< (elem); } template static typename if_can_take_address::type access (SRC&& elem) { std::cerr << "address-"<()<<" && ->"<()<::access (&elem); } template static typename if_can_dereference::type access (SRC&& elem) { std::cerr << "deref-"<()<<" && ->"<()<::access (*elem); } /** catch-all to signal failure of conversion */ static TAR access (...) { // NOTE: if you see this assertion failure, none of the above predicates were true. // Chances are that you requested a conversion that is logically impossible or dangerous, // like e.g. taking a reference from an anonymous value parameter static_assert (!sizeof(TAR), "AccessCasted: No valid conversion or cast supported for these types."); throw error::Invalid("impossible or unsafe type conversion requested"); } }; } // namespace util #endif