LUMIERA.clone/src/lib/access-casted-o.hpp
Ichthyostega 5d056f032d phase out the (now obsoleted) old Variant and AccessCasted implementation
All relevant uses will rely on the more strict access policy
implemented with the new util::AccessCasted. Along the same line
of thinking, I've removed the "second try" convenience conversion
from the typed get-Function of OpaqueHolder. Such an unbounded
"convert it somehow" approach is almost never a good idea. Either,
one knows by design the precise type to expect, or alternatively
should rely on the base interface solely.

...with the sole exception of the usage in WrapperPointer,
which in itself looks obsolete to me; we should better re-think
the way we handle "wrapped" objects for the BuilderTools, once
we actually start implementing the Builder

Ticket #450
2015-04-28 04:49:08 +02:00

172 lines
5.2 KiB
C++

/*
ACCESS-CASTED.hpp - util template to access a value using conversion or cast as appropriate
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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-o.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<TAR>, we get a template static function
** \c AcessCasted<TAR>::access<SRC>(SRC& elm), but the actual implementation
** is chosen using std::type_traits. If no sensible implementation can be
** selected, \c EmptyVal<TAR>::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.
**
** @deprecated old obsolete version ///////////////////////////////////////////TICKET #738 clean-up access-casted, rewrite variant (4/2015)
** @todo This is the obsoleted old version: It was excessively permissive, which
** I've learned to view as a danger, since it encourages a sloppy programming style.
** @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_O_H
#define UTIL_ACCESS_CASTED_O_H
#include <type_traits>
namespace util {
namespace {
using std::remove_pointer;
using std::remove_reference;
using std::is_convertible;
using std::is_polymorphic;
using std::is_base_of;
template <typename SRC, typename TAR>
struct can_cast : std::false_type {};
template <typename SRC, typename TAR>
struct can_cast<SRC*,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC*&,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC&,TAR&> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename T>
struct hasRTTI
{
typedef typename remove_pointer<
typename remove_reference<T>::type>::type TPlain;
enum { value = is_polymorphic<TPlain>::value };
};
template <typename SRC, typename TAR>
struct use_dynamic_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& hasRTTI<SRC>::value
&& hasRTTI<TAR>::value
};
};
template <typename SRC, typename TAR>
struct use_static_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& ( !hasRTTI<SRC>::value
|| !hasRTTI<TAR>::value
)
};
};
template <typename SRC, typename TAR>
struct use_conversion
{
enum { value = is_convertible<SRC,TAR>::value
&& !( use_static_downcast<SRC,TAR>::value
||use_dynamic_downcast<SRC,TAR>::value
)
};
};
template<typename X>
struct EmptyVal
{
static X create() { return X(); }
};
template<typename X>
struct EmptyVal<X*&>
{
static X*& create() { static X* nullP(0); return nullP; }
};
}
template<typename RET>
struct NullAccessor
{
typedef RET Ret;
static RET access (...) { return ifEmpty(); }
static RET ifEmpty () { return EmptyVal<RET>::create(); }
};
template<typename TAR>
struct AccessCasted_O : NullAccessor<TAR>
{
using NullAccessor<TAR>::access;
template<typename ELM>
static typename std::enable_if< use_dynamic_downcast<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{
return dynamic_cast<TAR> (elem);
}
template<typename ELM>
static typename std::enable_if< use_static_downcast<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{
return static_cast<TAR> (elem);
}
template<typename ELM>
static typename std::enable_if< use_conversion<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{
return elem;
}
};
} // namespace util
#endif