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
This commit is contained in:
Fischlurch 2015-04-28 04:49:08 +02:00
parent 250a5519de
commit 5d056f032d
4 changed files with 108 additions and 139 deletions

View file

@ -27,7 +27,7 @@
** 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 boost::type_traits. If no sensible implementation can be
** 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,
@ -45,89 +45,85 @@
#ifndef UTIL_ACCESS_CASTED_O_H
#define UTIL_ACCESS_CASTED_O_H
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <type_traits>
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 <typename SRC, typename TAR>
struct can_cast : boost::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 has_RTTI
{
typedef typename remove_pointer<
typename remove_reference<T>::type>::type TPlain;
namespace {
using std::remove_pointer;
using std::remove_reference;
using std::is_convertible;
using std::is_polymorphic;
using std::is_base_of;
enum { value = is_polymorphic<TPlain>::value };
};
template <typename SRC, typename TAR>
struct use_dynamic_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& has_RTTI<SRC>::value
&& has_RTTI<TAR>::value
};
};
template <typename SRC, typename TAR>
struct use_static_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& ( !has_RTTI<SRC>::value
|| !has_RTTI<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
)
};
};
////////////////////////////////TODO: use lib::NullValue instead
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 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; }
};
}
@ -142,12 +138,12 @@ namespace util {
};
template<typename TAR>
struct AccessCasted : NullAccessor<TAR>
struct AccessCasted_O : NullAccessor<TAR>
{
using NullAccessor<TAR>::access;
template<typename ELM>
static typename enable_if< use_dynamic_downcast<ELM&,TAR>,
static typename std::enable_if< use_dynamic_downcast<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{
@ -155,7 +151,7 @@ namespace util {
}
template<typename ELM>
static typename enable_if< use_static_downcast<ELM&,TAR>,
static typename std::enable_if< use_static_downcast<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{
@ -163,7 +159,7 @@ namespace util {
}
template<typename ELM>
static typename enable_if< use_conversion<ELM&,TAR>,
static typename std::enable_if< use_conversion<ELM&,TAR>::value,
TAR >::type
access (ELM& elem)
{

View file

@ -69,7 +69,7 @@
#include "lib/error.hpp"
#include "lib/bool-checkable.hpp"
#include "lib/access-casted-o.hpp"
#include "lib/access-casted.hpp"
#include "lib/util.hpp"
#include <type_traits>
@ -78,7 +78,8 @@
namespace lib {
using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
namespace error = lumiera::error;
using util::isSameObject;
using util::unConst;
@ -131,26 +132,9 @@ namespace lib {
if (asBase)
return asBase;
throw lumiera::error::Logic ("Unable to convert concrete object to Base interface"
, LUMIERA_ERROR_WRONG_TYPE
);
}
template<class SUB>
static SUB*
access (Base* asBase)
{
// Because we don't know anything about the involved types,
// we need to exclude a brute force static cast
// (which might slice or reinterpret or even cause SEGV)
if (!util::use_static_downcast<Base*,SUB*>::value)
{
SUB* content = util::AccessCasted<SUB*>::access (asBase);
return content;
// might be NULL
}
else
return 0;
throw error::Logic ("Unable to convert concrete object to Base interface"
, error::LUMIERA_ERROR_WRONG_TYPE
);
}
};
@ -175,13 +159,6 @@ namespace lib {
{
return static_cast<void*> (&obj);
}
template<class SUB>
static SUB*
access (Base*)
{
return 0;
}
};
@ -241,7 +218,8 @@ namespace lib {
BaseP
getBase() const
{
throw lumiera::error::Invalid("accessing empty holder");
throw error::Invalid("accessing empty holder"
, error::LUMIERA_ERROR_BOTTOM_VALUE);
}
virtual void
@ -455,19 +433,12 @@ namespace lib {
/** re-accessing the concrete contained object.
* When the specified type is exactly the same
* as used when storing the object, we can directly
* re-access the buffer. Otherwise, a conversion might
* be possible going through the Base type, depending
* on the actual types involved and the AccessPolicy.
* But, as we don't "know" the actual type of the object
* in storage, a \em static upcast to any type \em between
* the concrete object type and the base type has to be
* ruled out for safety reasons. When the contained object
* has RTTI, a \em dynamic cast can be performed in this
* situation. You might consider using visitor.hpp instead
* if this imposes a serious limitation.
* @throws lumiera::error::Logic when conversion/access fails
* This requires exact knowledge of the actual type
* of the element currently in storage. OpaqueHolder
* does not provide any "probing" or visitation mechanism.
* @remarks You might consider lib::Variant or some visitor instead.
* @throws lumiera::error::Logic when conversion/access fails
* @throws lumiera::error::Invalid when accessing an empty holder
*/
template<class SUB>
SUB& get() const
@ -479,16 +450,14 @@ namespace lib {
if (actual)
return actual->get();
// second try: maybe we can perform a dynamic downcast
// or direct conversion to the actual target type.
SUB* content = AccessPolicy::template access<SUB> (asBase());
if (content)
return *content;
throw lumiera::error::Logic ("Attempt to access OpaqueHolder's contents "
"specifying incompatible target type"
, LUMIERA_ERROR_WRONG_TYPE
);
if (this->empty())
throw error::Invalid("accessing empty holder"
, error::LUMIERA_ERROR_BOTTOM_VALUE);
else
throw error::Logic ("Attempt to access OpaqueHolder's contents "
"specifying incompatible target type"
, error::LUMIERA_ERROR_WRONG_TYPE
);
}

View file

@ -58,8 +58,11 @@ namespace lumiera {
* Later on, stored values can be retrieved either utilising static or dynamic casts;
* error reporting is similar to the behaviour of dynamic_cast<T>: when retrieving
* a pointer, NULL is returned in case of mismatch.
*
* @deprecated not sure if this was a good idea anyway. Better re-think how to handle wrapped objects in visitation
* @todo really need to switch to the new lib::Variant and util::AccessCasted implementation ////////////////TICKET #450
*/
typedef lib::VariantO<proc::WrapperTypes, util::AccessCasted> WrapperPtr;
typedef lib::VariantO<proc::WrapperTypes, util::AccessCasted_O> WrapperPtr;

View file

@ -41,8 +41,9 @@ namespace test{
using util::isnil;
using util::for_each;
using util::isSameObject;
using lumiera::error::LUMIERA_ERROR_INVALID;
using lumiera::error::LUMIERA_ERROR_ASSERTION;
using error::LUMIERA_ERROR_BOTTOM_VALUE;
using error::LUMIERA_ERROR_WRONG_TYPE;
using error::LUMIERA_ERROR_ASSERTION;
using std::vector;
using std::cout;
@ -216,7 +217,7 @@ namespace test{
oo.clear();
CHECK (!oo);
CHECK (isnil(oo));
VERIFY_ERROR (INVALID, oo.get<D5>() );
VERIFY_ERROR (BOTTOM_VALUE, oo.get<D5>() );
#if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
VERIFY_ERROR (ASSERTION, oo->getIt() );
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT