special case: support cloning, but not copy
needed to add yet another policy template, so PolymorphicValue doesn't invoke the assignment operator in such cases
This commit is contained in:
parent
6daf14211b
commit
6fa11ffcf6
3 changed files with 121 additions and 7 deletions
|
|
@ -60,9 +60,25 @@
|
|||
** specific function signature and then try to assign the named member. This allows even
|
||||
** to determine if a member function of a type in question has the desired signature.
|
||||
**
|
||||
** All these detection building blocks are written such as to provide a bool member \v ::value,
|
||||
** All these detection building blocks are written such as to provide a bool member \c ::value,
|
||||
** which is in accordance to the conventions of boost metaprogramming. I.e. you can immediately
|
||||
** use them within boost::enable_if
|
||||
** use them within \c boost::enable_if
|
||||
**
|
||||
** \par some pitfalls to consider
|
||||
**
|
||||
** @warning The generated metafunctions all yield the \c false value by default.
|
||||
** Effectively this means that an error in the test expression might go unnoticed;
|
||||
** you'd be better off explicitly checking the detection result by an unit test.
|
||||
**
|
||||
** There are several typical problems to care about
|
||||
** - a member can be both a variable or a function of that name
|
||||
** - function signatures need to match precisely, including const modifiers
|
||||
** - the generated metafunction (template) uses a type parameter 'TY', which could
|
||||
** shadow or conflict with an type parameter in the enclosing scope
|
||||
** - the member and function checks rely on member pointers, which generally rely on
|
||||
** the explicit static type. These checks don't see any inherited members / functions.
|
||||
** - obviously, all those checks are never able to detect anything depending on runtime
|
||||
** types or RTTI
|
||||
**
|
||||
** @see util-foreach.hpp usage example
|
||||
** @see duck-detector-test.cpp
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ namespace lib {
|
|||
|
||||
namespace polyvalue { // implementation details...
|
||||
|
||||
namespace error = lumiera::error;
|
||||
using boost::enable_if;
|
||||
using lumiera::Yes_t;
|
||||
using lumiera::No_t;
|
||||
|
|
@ -186,6 +187,21 @@ namespace lib {
|
|||
virtual void copyInto (IFA& targetBase) const =0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A variation for limited copy support.
|
||||
* Sometimes, only cloning (copy construction) of value objects is allowed,
|
||||
* but not assignment of new values to existing objects. In this case, the
|
||||
* concrete values can inherit from this variant of the support API.
|
||||
*/
|
||||
template<class BA> ///< direct baseclass to use for this clone support API
|
||||
class CloneValueSupport
|
||||
: public BA
|
||||
{
|
||||
public:
|
||||
virtual ~CloneValueSupport() { };
|
||||
virtual void cloneInto (void* targetBuffer) const =0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -193,7 +209,7 @@ namespace lib {
|
|||
* to support clone operations
|
||||
*/
|
||||
template<typename T>
|
||||
class exposes_copySupportFunctions
|
||||
class exposes_CloneFunction
|
||||
{
|
||||
|
||||
META_DETECT_FUNCTION(void, cloneInto, (void*) const);
|
||||
|
|
@ -203,8 +219,58 @@ namespace lib {
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* helper to detect if the API supports only
|
||||
* copy construction, but no assignment
|
||||
*/
|
||||
template<typename T>
|
||||
class allow_Clone_but_no_Copy
|
||||
{
|
||||
META_DETECT_MEMBER(copyInto);
|
||||
|
||||
public:
|
||||
enum{ value = exposes_CloneFunction<T>::value
|
||||
&& ! HasMember_copyInto<T>::value
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Policy class for invoking the assignment operator.
|
||||
* By default the embedded payload objects are assumed
|
||||
* to be freely assignable
|
||||
*/
|
||||
template<class API, class YES =void>
|
||||
struct AssignmentPolicy
|
||||
{
|
||||
template<class IMP>
|
||||
static void
|
||||
assignEmbedded(IMP& dest,IMP const& src)
|
||||
{
|
||||
dest = src;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* special case when the embedded payload objects permit
|
||||
* copy construction, but no assignment to existing instances.
|
||||
* Instead of invoking the assignment operator (which typically
|
||||
* isn't defined at all in such cases), a misguided assignment
|
||||
* to the container will raise an exception
|
||||
*/
|
||||
template<class API>
|
||||
struct AssignmentPolicy<API, typename enable_if< allow_Clone_but_no_Copy<API> >::type>
|
||||
{
|
||||
template<class IMP>
|
||||
static void
|
||||
assignEmbedded(IMP&,IMP const&)
|
||||
{
|
||||
throw error::Logic("attempt to overwrite unmodifiable value");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* traits template to deal with
|
||||
* different ways to support copy operations.
|
||||
* Default is no support by the API and implementation types.
|
||||
|
|
@ -226,6 +292,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
typedef CopyAPI AdapterAttachment;
|
||||
typedef AssignmentPolicy<CopyAPI> Assignment;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -237,7 +304,7 @@ namespace lib {
|
|||
* simple \c static_cast without runtime overhead.
|
||||
*/
|
||||
template <class TY>
|
||||
struct Trait<TY, typename enable_if< exposes_copySupportFunctions<TY> >::type>
|
||||
struct Trait<TY, typename enable_if< exposes_CloneFunction<TY> >::type>
|
||||
{
|
||||
typedef TY CopyAPI;
|
||||
enum{ ADMIN_OVERHEAD = 1 * sizeof(void*) };
|
||||
|
|
@ -251,6 +318,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
typedef EmptyBase AdapterAttachment;
|
||||
typedef AssignmentPolicy<CopyAPI> Assignment;
|
||||
};
|
||||
|
||||
}//(End)implementation details
|
||||
|
|
@ -259,6 +327,10 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Template to build polymorphic value objects.
|
||||
* Inline buffer with value semantics, yet holding and owning an object
|
||||
|
|
@ -285,6 +357,7 @@ namespace lib {
|
|||
|
||||
typedef polyvalue::Trait<CPY> _Traits;
|
||||
typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
|
||||
typedef typename _Traits::Assignment _AssignmentPolicy;
|
||||
enum{
|
||||
siz = storage + _Traits::ADMIN_OVERHEAD
|
||||
};
|
||||
|
|
@ -363,8 +436,8 @@ namespace lib {
|
|||
{
|
||||
REQUIRE (INSTANCEOF (Adapter, &targetBase));
|
||||
Adapter& target = static_cast<Adapter&> (targetBase);
|
||||
target = (*this); // forward to assignment operator
|
||||
}
|
||||
_AssignmentPolicy::assignEmbedded(target,*this);
|
||||
} // forward to assignment operator
|
||||
|
||||
public: /* == forwarding ctor to implementation type == */
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ namespace test{
|
|||
CHECK (0 == _checkSum); // all dead
|
||||
|
||||
verifyOverrunProtection();
|
||||
verifyCopySupportDetectionMetafunctions();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -277,6 +278,30 @@ namespace test{
|
|||
VERIFY_ERROR (ASSERTION, PolyVal::build<OversizedImp>() );
|
||||
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
|
||||
}
|
||||
|
||||
|
||||
/** @Test internally, PolymorphicValue uses some metafunctions
|
||||
* to pick a suitable code path, based on the presence of helper functions
|
||||
* on the API of the embedded objects. Default is no support by these objects,
|
||||
* which then requires to use a more expensive implementation. Sometimes it's
|
||||
* desirable to support \em cloning only (copy ctor), but no assignment after
|
||||
* the fact. In this special case, a support API with only a \cloneInto member
|
||||
* can be implemented, causing the PolymorphicValue container to raise an
|
||||
* exception in case the copy operator is invoked.
|
||||
*/
|
||||
void
|
||||
verifyCopySupportDetectionMetafunctions()
|
||||
{
|
||||
typedef polyvalue::CopySupport<Interface> CopySupportAPI;
|
||||
typedef polyvalue::CloneValueSupport<Interface> CloneOnlyAPI;
|
||||
|
||||
CHECK ( !polyvalue::exposes_CloneFunction<Interface>::value );
|
||||
CHECK ( polyvalue::exposes_CloneFunction<CopySupportAPI>::value );
|
||||
CHECK ( polyvalue::exposes_CloneFunction<CloneOnlyAPI>::value );
|
||||
|
||||
CHECK ( polyvalue::allow_Clone_but_no_Copy<CloneOnlyAPI>::value );
|
||||
CHECK ( !polyvalue::allow_Clone_but_no_Copy<CopySupportAPI>::value );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue