clean-up: trash ReplacableItem (closes: #1059)
Now looking into largely obsolete library facilities... Starting from `ScopedHolder`, I found a surprising problem with ''perfect forwarding....'' ...which however turned out to be the result of ''sloppy programming'' on my side. At that time, in 2017, seemingly I was under pressure to define a Session-Command, which captures a Time-entity as »State Memento«. Which turned out to be impossible, since the Time entities were conceived as being immutable -- a questionable design decision (see #1261), which already generated quite some additional complexities. In the course of this »exercise«, I could again clarify that the implementation of perfect forwarding works as expected on modern compilers — confusion may arrise sometimes due to ''copy elision'' (which the compiler is required to perform since C++17, even when the elided constructor has observable side effects). And it can be derailed when (as was the case here) a »grab everything« constructor accidentally ends up generating a copy- or move-constructor for the container class itself. This is an instance of the problem documented with #963 ... .... and the best solution is to abide by the rule-of-five (and a half) and to put that `ReplacableItem` to where it belongs...
This commit is contained in:
parent
11322ad955
commit
bc6a219543
7 changed files with 182 additions and 575 deletions
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
REPLACEABLE-ITEM.hpp - adapter to take snapshot from non-assignable values
|
||||
|
||||
Copyright (C)
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** 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. See the file COPYING for further details.
|
||||
|
||||
*/
|
||||
|
||||
/** @file replaceable-item.hpp
|
||||
** Adapter wrapper to treat non-assignable values as if they were assignable.
|
||||
** Prerequisite is for the type to be copy constructible (maybe even just move constructible).
|
||||
** The typical usage is when we want to take a _snapshot_ from some value, but do not actually
|
||||
** need the ability to assign something to a specific object instance. In such a situation,
|
||||
** we may just destroy a previous snapshot and then place a new copy initialised value into
|
||||
** the same storage space. For all really assignable types we fall back to a trivial
|
||||
** implementation.
|
||||
**
|
||||
** \par motivation
|
||||
** The typical usage is in library or framework code, where we do not know what types to expect.
|
||||
** For example, the Lumiera command framework automatically captures an _UNDO memento_ based
|
||||
** on the return type of a state capturing function. It would be highly surprising for the
|
||||
** user if it wasn't possible to capture e.g. time values or durations as _old state_,
|
||||
** because these entities can not be re-assigned with new values, only created.
|
||||
** But obviously a command handling framework needs the ability to capture
|
||||
** state consecutively several times, and this adapter was created
|
||||
** to bridge this conceptual discrepancy
|
||||
**
|
||||
** \par extensions
|
||||
** - the type can be solely move constructible, in which case the payload needs to be
|
||||
** moved explicitly when embedding into this adapter ///////////////////////////////////////////////TICKET 1059 : does not work yet on GCC-4.9
|
||||
** - when the payload is equality comparable, the container is as well, by delegation
|
||||
** - container instances can be default created, which emplaces an _empty value_.
|
||||
** The actual value to embed is retrieved from the lib::NullValue template,
|
||||
** which is a static per-type singleton.
|
||||
** - thus types which are not even default constructible can still be used,
|
||||
** by providing an explicit specialisation of lib::NullValue for this type.
|
||||
**
|
||||
** @see ReplaceableIterm_test
|
||||
** @see steam::control::MementoTie
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_REPLACEABLE_ITEM_H
|
||||
#define LIB_REPLACEABLE_ITEM_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/null-value.hpp"
|
||||
#include "lib/meta/util.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace wrapper {
|
||||
|
||||
using util::isSameObject;
|
||||
using util::unConst;
|
||||
using std::forward;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adapter container to take snapshots from non-assignable values.
|
||||
* Implemented by placing the subject into an inline buffer.
|
||||
* @note uses lib::NullValue to retrieve an _empty payload_.
|
||||
*/
|
||||
template<typename X, typename COND =void>
|
||||
class ReplaceableItem
|
||||
{
|
||||
alignas(X)
|
||||
std::byte content_[sizeof(X)];
|
||||
|
||||
public:
|
||||
ReplaceableItem()
|
||||
{
|
||||
emplace (NullValue<X>::get());
|
||||
}
|
||||
~ReplaceableItem()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
template<typename Z>
|
||||
ReplaceableItem (Z&& otherValue)
|
||||
{
|
||||
emplace (forward<Z> (otherValue));
|
||||
}
|
||||
|
||||
template<typename Z>
|
||||
ReplaceableItem&
|
||||
operator= (Z&& otherValue)
|
||||
{
|
||||
if (not isSameObject(*this, otherValue))
|
||||
reAssign (forward<Z> (otherValue));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReplaceableItem&
|
||||
clear() noexcept
|
||||
{
|
||||
reAssign (NullValue<X>::get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator X&() { return access(); }
|
||||
operator X const&() const { return unConst(this)->access(); }
|
||||
|
||||
X& get() { return access(); }
|
||||
X const& get() const { return unConst(this)->access(); }
|
||||
|
||||
|
||||
private:
|
||||
X&
|
||||
access()
|
||||
{
|
||||
return * std::launder (reinterpret_cast<X*> (&content_));
|
||||
}
|
||||
|
||||
void
|
||||
destroy()
|
||||
{
|
||||
access().~X();
|
||||
}
|
||||
|
||||
template<typename Z>
|
||||
void
|
||||
emplace (Z&& otherValue)
|
||||
try {
|
||||
new(&content_) X{forward<Z> (otherValue)};
|
||||
}
|
||||
catch(...) {
|
||||
new(&content_) X{NullValue<X>::get()};
|
||||
}
|
||||
|
||||
template<typename Z>
|
||||
void
|
||||
reAssign (Z&& otherValue)
|
||||
{
|
||||
destroy();
|
||||
emplace (forward<Z> (otherValue));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename X>
|
||||
struct is_assignable_value
|
||||
: std::__and_<std::is_copy_assignable<X>, std::__not_<std::is_reference<X>>>
|
||||
{ };
|
||||
|
||||
/**
|
||||
* simple delegating implementation
|
||||
* to use for regular cases
|
||||
*/
|
||||
template<typename X>
|
||||
class ReplaceableItem<X, meta::enable_if<is_assignable_value<X>>>
|
||||
{
|
||||
X val_;
|
||||
|
||||
public:
|
||||
ReplaceableItem() : val_(NullValue<X>::get()) { }
|
||||
|
||||
ReplaceableItem(X const& val) : val_(val) { }
|
||||
ReplaceableItem(X && val) : val_(forward<X>(val)) { }
|
||||
|
||||
ReplaceableItem& operator= (X const& val) { val_=val; return *this; }
|
||||
ReplaceableItem& operator= (X && val) { val_=forward<X>(val); return *this; }
|
||||
ReplaceableItem& clear() noexcept { val_=NullValue<X>::get(); return *this; }
|
||||
|
||||
operator X&() { return val_; }
|
||||
operator X const&() const { return val_; }
|
||||
|
||||
X& get() { return val_; }
|
||||
X const& get() const { return val_; }
|
||||
};
|
||||
|
||||
|
||||
/** disallow embedding references */
|
||||
template<typename X>
|
||||
class ReplaceableItem<X, meta::enable_if<std::is_reference<X>>>
|
||||
{
|
||||
static_assert( not sizeof(X), "ReplaceableItem for references is pointless");
|
||||
};
|
||||
|
||||
|
||||
/* ===== Equality comparison delegated to contained element ===== */
|
||||
|
||||
template<typename X>
|
||||
inline bool
|
||||
operator== (ReplaceableItem<X> const& li, ReplaceableItem<X> const& ri)
|
||||
{
|
||||
return li.get() == ri.get();
|
||||
}
|
||||
template<typename X>
|
||||
inline bool
|
||||
operator!= (ReplaceableItem<X> const& li, ReplaceableItem<X> const& ri)
|
||||
{
|
||||
return li.get() != ri.get();
|
||||
}
|
||||
|
||||
template<typename X, typename Z>
|
||||
inline bool
|
||||
operator== (ReplaceableItem<X> const& item, Z const& something)
|
||||
{
|
||||
return item.get() == something;
|
||||
}
|
||||
template<typename X, typename Z>
|
||||
inline bool
|
||||
operator!= (ReplaceableItem<X> const& item, Z const& something)
|
||||
{
|
||||
return item.get() != something;
|
||||
}
|
||||
|
||||
template<typename Z, typename X>
|
||||
inline bool
|
||||
operator== (Z const& something, ReplaceableItem<X> const& item)
|
||||
{
|
||||
return item.get() == something;
|
||||
}
|
||||
template<typename Z, typename X>
|
||||
inline bool
|
||||
operator!= (Z const& something, ReplaceableItem<X> const& item)
|
||||
{
|
||||
return item.get() != something;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::wrap
|
||||
#endif /*LIB_REPLACEABLE_ITEM_H*/
|
||||
|
|
@ -34,7 +34,8 @@
|
|||
#include "lib/meta/maybe-compare.hpp"
|
||||
#include "lib/meta/function-closure.hpp"
|
||||
#include "steam/control/command-signature.hpp"
|
||||
#include "lib/replaceable-item.hpp"
|
||||
//#include "lib/replaceable-item.hpp"
|
||||
#include "lib/wrapper.hpp"
|
||||
#include "lib/format-obj.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
@ -51,7 +52,7 @@ namespace control {
|
|||
using lib::meta::func::bindLast;
|
||||
using lib::meta::func::chained;
|
||||
using lib::meta::equals_safeInvoke;
|
||||
using lib::wrapper::ReplaceableItem;
|
||||
using lib::wrapper::ItemWrapper;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -82,7 +83,7 @@ namespace control {
|
|||
typedef typename CommandSignature<SIG,MEM>::CaptureSig SIG_cap;
|
||||
typedef typename CommandSignature<SIG,MEM>::UndoOp_Sig SIG_undo;
|
||||
|
||||
ReplaceableItem<MEM> memento_; ///< storage holding the captured state for undo
|
||||
ItemWrapper<MEM> memento_; ///< storage holding the captured state for undo
|
||||
|
||||
bool isCaptured_;
|
||||
|
||||
|
|
@ -110,10 +111,10 @@ namespace control {
|
|||
*/
|
||||
MementoTie (function<SIG_undo> const& undoFunc,
|
||||
function<SIG_cap> const& captureFunc)
|
||||
: memento_()
|
||||
, isCaptured_(false)
|
||||
, undo_(undoFunc)
|
||||
, capture_(captureFunc)
|
||||
: memento_{}
|
||||
, isCaptured_{false}
|
||||
, undo_{undoFunc}
|
||||
, capture_{captureFunc}
|
||||
{ }
|
||||
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ namespace control {
|
|||
clear()
|
||||
{
|
||||
isCaptured_ = false;
|
||||
memento_.clear();
|
||||
memento_.reset();
|
||||
}
|
||||
|
||||
/** bind the undo function to the internal memento store within this object.
|
||||
|
|
@ -163,10 +164,10 @@ namespace control {
|
|||
MEM&
|
||||
getState ()
|
||||
{
|
||||
if (!isCaptured_)
|
||||
if (not isCaptured_)
|
||||
throw err::State{"need to invoke memento state capturing beforehand"
|
||||
, LERR_(MISSING_MEMENTO)};
|
||||
return memento_;
|
||||
return *memento_;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -183,7 +184,7 @@ namespace control {
|
|||
bool
|
||||
isValid () const
|
||||
{
|
||||
return undo_ && capture_ && isCaptured_;
|
||||
return undo_ and capture_ and isCaptured_;
|
||||
}
|
||||
|
||||
/** for diagnostics: include format-util.hpp */
|
||||
|
|
@ -195,14 +196,14 @@ namespace control {
|
|||
template<typename SIG, typename MEM>
|
||||
MementoTie<SIG,MEM>::operator std::string() const
|
||||
{
|
||||
if (!undo_ || !capture_)
|
||||
if (!undo_ or !capture_)
|
||||
return "·noUNDO·";
|
||||
|
||||
if (!isCaptured_)
|
||||
if (not isCaptured_)
|
||||
return "<mem:missing>";
|
||||
|
||||
return "<mem: "
|
||||
+ util::toString (memento_.get())
|
||||
+ util::toString (*memento_)
|
||||
+ ">";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -527,11 +527,6 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "inline adapter for state snapshot" ReplaceableItem_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "switchable reference" OptionalRef_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
|
|
@ -95,19 +95,6 @@ namespace test {
|
|||
template<typename TY>
|
||||
int Tracker<TY>::instanceCnt (0);
|
||||
|
||||
/** prepare a (singleton) _empty value_ for the memento.
|
||||
* @remarks This is done prior to observing the Tracker instanceCnt,
|
||||
* because this empty value obviously remains allocated forever.
|
||||
* The memento is stored within a [special holder](\ref lib::ReplaceableItem)
|
||||
* to allow capturing memento state even from immutable values, which only can
|
||||
* be copy constructed. This mechanism uses lib::NullValue to retrieve an
|
||||
* empty placeholder value when the memento has not yet been captured.
|
||||
*/
|
||||
void
|
||||
prepareEmptyMemento()
|
||||
{
|
||||
lib::NullValue<Tracker<string>>::get();
|
||||
}
|
||||
|
||||
/** Dummy custom memento datatype
|
||||
* @note memento needs to be equality comparable
|
||||
|
|
@ -202,7 +189,6 @@ namespace test {
|
|||
{
|
||||
seedRand();
|
||||
ArgTuples testTuples;
|
||||
prepareEmptyMemento();
|
||||
Tracker<TimeVar>::instanceCnt = 0;
|
||||
Tracker<string>::instanceCnt = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -92,10 +92,6 @@ namespace test {
|
|||
|
||||
MemHolder mementoHolder (undo_func,cap_func);
|
||||
|
||||
CHECK (sizeof(MemHolder) <= sizeof(int) // storage for the memento
|
||||
+ 2 * sizeof(function<void()>) // storage for the 2 undecorated functors
|
||||
+ ALIGNMENT);
|
||||
|
||||
function<OpSIG> bound_undo_func = mementoHolder.tieUndoFunc();
|
||||
function<OpSIG> bound_cap_func = mementoHolder.tieCaptureFunc();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,297 +0,0 @@
|
|||
/*
|
||||
ReplaceableItem(Test) - adapter to take snapshot from non-assignable values
|
||||
|
||||
Copyright (C)
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** 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. See the file COPYING for further details.
|
||||
|
||||
* *****************************************************************/
|
||||
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
#include "lib/replaceable-item.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace wrapper {
|
||||
namespace test{
|
||||
|
||||
using ::Test;
|
||||
using lib::test::randStr;
|
||||
using lib::test::randTime;
|
||||
using util::isSameObject;
|
||||
|
||||
using time::Time;
|
||||
using time::Duration;
|
||||
using std::string;
|
||||
using std::swap;
|
||||
|
||||
|
||||
|
||||
namespace { // Test helper: yet another ctor/dtor counting class
|
||||
|
||||
long cntTracker = 0;
|
||||
|
||||
struct Tracker
|
||||
{
|
||||
uint i_;
|
||||
|
||||
Tracker() : i_(rani(500)) { ++cntTracker; }
|
||||
Tracker(Tracker const& ot) : i_(ot.i_) { ++cntTracker; }
|
||||
Tracker(uint i) : i_(i) { ++cntTracker; }
|
||||
~Tracker() { --cntTracker; }
|
||||
|
||||
Tracker& operator= (Tracker const&) = default;
|
||||
};
|
||||
|
||||
struct NonAssign
|
||||
: Tracker
|
||||
{
|
||||
using Tracker::Tracker;
|
||||
NonAssign& operator= (NonAssign const&) =delete;
|
||||
};
|
||||
|
||||
|
||||
bool operator== (Tracker const& t1, Tracker const& t2) { return t1.i_ == t2.i_; }
|
||||
bool operator!= (Tracker const& t1, Tracker const& t2) { return t1.i_ != t2.i_; }
|
||||
|
||||
} // (END) Test helpers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************//**
|
||||
* @test scrutinise an adapter to snapshot non-assignable values.
|
||||
* - create instantiations for various types
|
||||
* - both assignable and non-assignable types
|
||||
* - empty-construct and copy construct the adapter
|
||||
* - perform assignments and even content swapping
|
||||
* - use counting to verify proper instance management
|
||||
* - compare by delegating to element comparison
|
||||
*
|
||||
* @see replaceable-item.hpp
|
||||
* @see steam::control::MementoTie
|
||||
*/
|
||||
class ReplaceableItem_test : public Test
|
||||
{
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
ulong l1 (1 + rani(1000));
|
||||
ulong l2 (1 + rani(1000));
|
||||
string s1 (randStr(50));
|
||||
string s2 (randStr(50));
|
||||
const char* cp (s1.c_str());
|
||||
|
||||
Time t1{randTime()}, t2{randTime()};
|
||||
Duration d1{randTime()}, d2{randTime()};
|
||||
|
||||
verifyUsage<ulong> (l1, l2);
|
||||
verifyUsage<ulong*> (&l1, &l2);
|
||||
|
||||
verifyUsage<string> (s1, s2);
|
||||
verifyUsage<string*> (&s1, &s2);
|
||||
|
||||
verifyUsage<string> (s2, cp);
|
||||
verifyUsage<string> (cp, "Lumiera");
|
||||
verifyUsage<const char*> (cp, "Lumiera");
|
||||
|
||||
// non-assignable types...
|
||||
verifyUsage<Time> (t1, t2);
|
||||
verifyUsage<Time> (t1, d1);
|
||||
verifyUsage<Duration> (d1, t2);
|
||||
verifyUsage<Duration> (d1, d2);
|
||||
|
||||
verifyNonComparableElements();
|
||||
verifyOnlyMoveConstructible();
|
||||
verifySaneInstanceHandling();
|
||||
verifyWrappedPtr ();
|
||||
}
|
||||
|
||||
|
||||
template<typename X, typename Y>
|
||||
void
|
||||
verifyUsage (X she, Y he)
|
||||
{
|
||||
using It = ReplaceableItem<X>;
|
||||
|
||||
It one{she}, two{he};
|
||||
REQUIRE (one != two);
|
||||
CHECK (two == he);
|
||||
CHECK (one == she);
|
||||
CHECK (sizeof(one) == sizeof(X));
|
||||
CHECK (sizeof(two) == sizeof(X));
|
||||
|
||||
It copy1{she};
|
||||
It copy2;
|
||||
|
||||
CHECK (one == copy1);
|
||||
CHECK (one != copy2);
|
||||
CHECK (two != copy1);
|
||||
CHECK (two != copy2);
|
||||
|
||||
CHECK (copy2 == NullValue<X>::get());
|
||||
|
||||
copy2 = he; // assign from value
|
||||
CHECK (one == copy1);
|
||||
CHECK (one != copy2);
|
||||
CHECK (two != copy1);
|
||||
CHECK (two == copy2);
|
||||
|
||||
std::swap (copy1, copy2); // possibly move construction / move assignment
|
||||
CHECK (one != copy1);
|
||||
CHECK (one == copy2);
|
||||
CHECK (two == copy1);
|
||||
CHECK (two != copy2);
|
||||
|
||||
copy1 = copy1; // self assignment (is skipped)
|
||||
copy2 = one; // assignment of an identical value
|
||||
|
||||
CHECK (copy1 == he);
|
||||
CHECK (copy2 == she);
|
||||
CHECK (one == she);
|
||||
CHECK (two == he);
|
||||
|
||||
copy1 = It{}; // copy assignment from anonymous holder
|
||||
CHECK (copy1 == NullValue<X>::get());
|
||||
CHECK (copy1 != he);
|
||||
};
|
||||
|
||||
|
||||
/** @test verify that ctor and dtor calls are balanced,
|
||||
* even when assigning and self-assigning.
|
||||
* @note Tracker uses the simple implementation for assignable values,
|
||||
* while NonAssign uses the embedded-buffer implementation
|
||||
*/
|
||||
void
|
||||
verifySaneInstanceHandling()
|
||||
{
|
||||
cntTracker = 0;
|
||||
{
|
||||
Tracker t1;
|
||||
Tracker t2;
|
||||
|
||||
verifyUsage<Tracker> (t1, t2);
|
||||
verifyUsage<Tracker*> (&t1, &t2);
|
||||
verifyUsage<Tracker> (t1, t2.i_);
|
||||
verifyUsage<Tracker, Tracker&> (t1, t2);
|
||||
|
||||
NonAssign u1;
|
||||
NonAssign u2;
|
||||
verifyUsage<NonAssign> (u1, u2);
|
||||
verifyUsage<NonAssign*> (&u1, &u2);
|
||||
verifyUsage<NonAssign> (u1, u2.i_);
|
||||
verifyUsage<NonAssign, NonAssign&> (u1, u2);
|
||||
verifyUsage<Tracker> (u1, u2);
|
||||
}
|
||||
CHECK (2 == cntTracker); // surviving singleton instances
|
||||
} // NullValue<Tracker> and NullValue<NonAssign>
|
||||
|
||||
|
||||
/** @test verify especially that we can handle and re-"assign" an embedded pointer */
|
||||
void
|
||||
verifyWrappedPtr ()
|
||||
{
|
||||
int x = 5;
|
||||
ReplaceableItem<int*> ptrWrap;
|
||||
CHECK (ptrWrap.get() == NULL);
|
||||
|
||||
ptrWrap = &x;
|
||||
CHECK (5 == *ptrWrap.get());
|
||||
CHECK (&x == ptrWrap.get());
|
||||
|
||||
*ptrWrap.get() += 5;
|
||||
CHECK (x == 10);
|
||||
|
||||
CHECK ( isSameObject (*ptrWrap.get(), x));
|
||||
CHECK (!isSameObject ( ptrWrap.get(), x));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test verify we can handle elements without comparison operator */
|
||||
void
|
||||
verifyNonComparableElements ()
|
||||
{
|
||||
struct Wrap
|
||||
{
|
||||
int i = -10 + rani(21);
|
||||
};
|
||||
|
||||
ReplaceableItem<Wrap> w1 =Wrap{},
|
||||
w2 =Wrap{};
|
||||
|
||||
int i = w1.get().i,
|
||||
j = w2.get().i;
|
||||
|
||||
swap (w1,w2);
|
||||
|
||||
CHECK (i == w2.get().i);
|
||||
CHECK (j == w1.get().i);
|
||||
|
||||
// w1 == w2; // does not compile since comparison of Wraps is undefined
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test handle elements that allow nothing but move construction
|
||||
* @todo conceptually, the whole point of this container is the ability
|
||||
* to snapshot elements which allow nothing but move construction.
|
||||
* Seemingly, GCC-4.9 does not fully implement perfect forwarding ///////////////////////TICKET #1059 : re-visit with never compiler
|
||||
*/
|
||||
void
|
||||
verifyOnlyMoveConstructible ()
|
||||
{
|
||||
struct Cagey
|
||||
{
|
||||
int i = -10 + rani(21);
|
||||
|
||||
Cagey(Cagey && privy)
|
||||
: i(55)
|
||||
{
|
||||
swap (i, privy.i);
|
||||
}
|
||||
// Cagey(Cagey const&) =delete; //////////////////////////////////////////TICKET #1059 : should be deleted for this test to make any sense
|
||||
Cagey(Cagey const&) =default;
|
||||
Cagey() =default;
|
||||
};
|
||||
|
||||
ReplaceableItem<Cagey> uc1 {std::move (Cagey{})},
|
||||
uc2 {std::move (Cagey{})};
|
||||
|
||||
int i = uc1.get().i,
|
||||
j = uc2.get().i;
|
||||
|
||||
swap (uc1,uc2); //////////////////////////////////////////TICKET #1059
|
||||
|
||||
CHECK (i == uc2.get().i);
|
||||
CHECK (j == uc1.get().i);
|
||||
|
||||
ReplaceableItem<Cagey> occult {std::move (uc1)}; //////////////////////////////////////////TICKET #1059 : should use the move ctor but uses the copy ctor
|
||||
CHECK (j == occult.get().i);
|
||||
// CHECK (55 == uc1.get().i); //////////////////////////////////////////TICKET #1059
|
||||
}
|
||||
};
|
||||
|
||||
LAUNCHER (ReplaceableItem_test, "unit common");
|
||||
|
||||
|
||||
}}} // namespace lib::wrapper::test
|
||||
|
||||
|
|
@ -163461,6 +163461,173 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1747180091430" ID="ID_202566672" MODIFIED="1747180099934" TEXT="was ist mit ScopedPtrvect?">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1748609941535" ID="ID_309992355" MODIFIED="1748609956540" TEXT="Status feststellen">
|
||||
<node CREATED="1748609976008" ID="ID_406349837" LINK="https://issues.lumiera.org/ticket/1059" MODIFIED="1748610043456" TEXT="#1059 verify and use perfect forwarding">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1748610060693" ID="ID_1805620153" MODIFIED="1748610070678" TEXT="damit noch markierte Stellen"/>
|
||||
<node CREATED="1748610072404" ID="ID_1048223493" MODIFIED="1748610074089" TEXT="ReplaceableItem">
|
||||
<node CREATED="1748610172811" ID="ID_1302490511" MODIFIED="1748610179076" TEXT="nur verwendet in MementoTie">
|
||||
<node CREATED="1748610357399" ID="ID_592334688" MODIFIED="1748615675308">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
»Commands« sind selber im <i>Schwebezustand</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Zwar halte ich Commands nicht für <i>insgesamt obsolet</i> — wir werden so etwas definitiv brauchen, da unser GUI per Messaging angebunden ist. Aber es ist bisher unklar geblieben, <i>wie die Schnittstelle zur Sessinon tatsächlich aussehen wird,</i> auf der die Command-Funktoren dann einmal arbeiten sollen. Zudem waren die Commands auch als Teil eines »Command-Systems« gedacht, welches auch UNDO und REDO ermöglicht. Und <i>in dieser Hinsicht</i> bewege ich mich schon seit längerer Zeit in Richtung auf <b>Events</b> und <b>Event-sourcing</b>. Damit wäre ein Großteil der Komplexität im bestehenden Command-Framework hinfällig
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1748614552731" ID="ID_346301743" LINK="https://issues.lumiera.org/ticket/1406" MODIFIED="1748614580419" TEXT="das als Ticket #1406 dokumentiert">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748615683688" ID="ID_30876581" MODIFIED="1748615697365" TEXT="emplace()-Funktion">
|
||||
<node CREATED="1748615698444" ID="ID_1303082006" MODIFIED="1748616023594" TEXT="Fallback-Implementierung ist zweifelhaft">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
pfui ... einen Konstruktor-Fehler unterdrücken und stattdessen ein default-konstruiertes Objekt unterschieben, und das auch noch in einer Funktion, die <font face="Monospaced"><b>emplace</b>()</font> heißt...
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node COLOR="#e304be" CREATED="1748616025456" HGAP="27" ID="ID_861306315" MODIFIED="1748622359848" TEXT="sowas hab ich 2017 geschrieben ???" VSHIFT="5">
|
||||
<arrowlink COLOR="#d20262" DESTINATION="ID_937835041" ENDARROW="Default" ENDINCLINATION="271;-18;" ID="Arrow_ID_40047268" STARTARROW="None" STARTINCLINATION="270;21;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="11"/>
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748615708061" ID="ID_1952799104" MODIFIED="1748615719258" TEXT="und bricht tatsächlich bei move-only payload"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748614957898" ID="ID_1767040619" MODIFIED="1748614982384" TEXT="hoppla ... da gibt es ja tatsächlich einen auskommentierten Testfall">
|
||||
<node CREATED="1748614996449" ID="ID_1125899180" MODIFIED="1748615007540" TEXT="ReplaceableItem_test::verifyOnlyMoveConstructible"/>
|
||||
<node CREATED="1748615728560" ID="ID_869271198" MODIFIED="1748615747564" TEXT="hatte damals Zweifel am Compiler"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1748616937343" ID="ID_1907997038" MODIFIED="1748616954102" STYLE="fork" TEXT="immer noch: sonderbares Verhalten des Compilers">
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1748616955995" ID="ID_1759129160" MODIFIED="1748616996939" TEXT=" wählt den deleted copy constructor"/>
|
||||
<node CREATED="1748616972914" ID="ID_1249573186" MODIFIED="1748616991994" TEXT="obwohl ein move-ctor explizit definiert wurde"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1748617034911" ID="ID_1469388650" MODIFIED="1748617042353" TEXT="untersuchen">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1748619335635" ID="ID_721492625" MODIFIED="1748621260565" TEXT="in try.cpp nicht ohne Weiteres reproduzierbar">
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1748620682218" ID="ID_1781899575" MODIFIED="1748620715236" TEXT="so exakt wie möglich extrahieren ⟹ Fehler nun reproduzierbar">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#d51d02" CREATED="1748621267614" ID="ID_1330365517" MODIFIED="1748622302088">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
ReplacableIterm ist <b>schlampig definiert</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
<node CREATED="1748621309800" ID="ID_1952174695" MODIFIED="1748621319170" TEXT="Rule-of-Five etc...."/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1748621320031" ID="ID_1206089903" MODIFIED="1748621346780" TEXT="der "move-ctor" ist tatsächlich ein take-everything-ctor">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1748621350195" ID="ID_1301662963" MODIFIED="1748621452771" TEXT="und wenn er zum move-ctor wird, dann ist er unsinnig implementiert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...denn er würde ReplacableItem in ein ReplacableItem einpflanzen — also <b>ein Stockwerk zu viel</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#d50277" CREATED="1748622317411" ID="ID_937835041" MODIFIED="1748622353471" TEXT="Historie / Hintergrund">
|
||||
<linktarget COLOR="#d20262" DESTINATION="ID_937835041" ENDARROW="Default" ENDINCLINATION="271;-18;" ID="Arrow_ID_40047268" SOURCE="ID_861306315" STARTARROW="None" STARTINCLINATION="270;21;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1748622369577" ID="ID_1844169551" MODIFIED="1748622390296" TEXT="an einem einzigen Tag durchgeprügelt (Jan.2017)">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
<node CREATED="1748622393804" ID="ID_1814476265" MODIFIED="1748622445242">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
wollte <b>Time</b>, <b>Duration</b> etc. in einem Command als Memento binden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d9c28d" COLOR="#a50125" CREATED="1748622481259" ID="ID_1066388646" LINK="https://issues.lumiera.org/ticket/1261" MODIFIED="1748622522979" TEXT="#1261 immutable Time considered harmful">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1748622539774" ID="ID_913302370" MODIFIED="1748622550271" TEXT="reparieren oder wegwerfen?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1748622575863" ID="ID_1364270668" MODIFIED="1748622595883" TEXT="krasse Diskrepanz zu dem was tatsächlich gebraucht wird">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1748622552618" ID="ID_1702305891" MODIFIED="1748622570467" TEXT="man könnte nämlich den ItemWrapper stattdessen nehmen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1748622617846" ID="ID_451189507" MODIFIED="1748622659320" TEXT="der ist zwar sehr viel mächtiger, wird aber auch sehr viel verwendet"/>
|
||||
<node CREATED="1748622665802" ID="ID_1153584758" MODIFIED="1748622719413" TEXT="und wird dadurch langsam »sauber geklopft«">
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
<node CREATED="1748622689989" HGAP="27" ID="ID_1342148038" MODIFIED="1748622714135" TEXT="war nämlich ebenso schlampig geschrieben" VSHIFT="5">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1748622735899" ID="ID_1255281715" MODIFIED="1748622746287" TEXT="also aufräumen">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#338800" CREATED="1748622748112" ID="ID_922876099" MODIFIED="1748623903974" TEXT="MementoTie umstellen auf ItemWrapper">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#c0c8b6" COLOR="#435e98" CREATED="1748623906654" ID="ID_640360358" MODIFIED="1748623941289" TEXT="banal ... in 5 Minuten erledigt">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748622765812" ID="ID_1447472606" MODIFIED="1748622792373" TEXT="Header aufräumen">
|
||||
<node CREATED="1748622795210" ID="ID_971344498" MODIFIED="1748622815722" TEXT="wrapper.hpp ⟼ item-wrapper.hpp"/>
|
||||
<node CREATED="1748622837148" ID="ID_1686776944" MODIFIED="1748622856501" TEXT="ReturnRef überflüssig machen"/>
|
||||
<node CREATED="1748622823574" ID="ID_518076065" MODIFIED="1748622828698" TEXT="Kommentar glattziehen"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1742175299968" ID="ID_1393531242" MODIFIED="1742175305316" TEXT="C++20">
|
||||
|
|
|
|||
Loading…
Reference in a new issue