Job-Planning: switch to processing references
...which uncovers further deeply nested problems, especially when referring to non-copyable types. Thus need to construct a common type that can be used both to refer to the source elements and the expanded elements, and use this common type as result type and also attempt to produce better diagnostic messages on type mismatch....
This commit is contained in:
parent
bf6951afcf
commit
94cec423d0
10 changed files with 476 additions and 103 deletions
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
FormatString - string template formatting based on boost::format
|
||||
FormatString - string template formatting based on boost::format
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -76,7 +76,7 @@ namespace util {
|
|||
inline void
|
||||
destroyImpl (char* buffer)
|
||||
{
|
||||
accessImpl(buffer).~format();
|
||||
accessImpl(buffer).~format();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ namespace util {
|
|||
suppressInsufficientArgumentErrors (char* formatter)
|
||||
{
|
||||
using namespace boost::io;
|
||||
accessImpl(formatter).exceptions (all_error_bits ^ too_few_args_bit);
|
||||
accessImpl(formatter).exceptions (all_error_bits ^ too_few_args_bit);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -129,8 +129,8 @@ namespace std { // forward declaration to avoid including <iostream>
|
|||
|
||||
|
||||
namespace lib {
|
||||
class Literal;
|
||||
class Symbol;
|
||||
class Literal;
|
||||
class Symbol;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ namespace util {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* A front-end for using printf-style formatting.
|
||||
* Values to be formatted can be supplied through the
|
||||
* operator%. Custom defined string conversions on objects
|
||||
|
|
@ -180,7 +180,7 @@ namespace util {
|
|||
~_Fmt ();
|
||||
_Fmt (string formatString);
|
||||
|
||||
operator string() const; ///< get the formatted result
|
||||
operator string() const; ///< get the formatted result
|
||||
|
||||
template<typename VAL>
|
||||
_Fmt&
|
||||
|
|
@ -209,8 +209,8 @@ namespace util {
|
|||
/* ===== forwarding into the implementation ====== */
|
||||
|
||||
/** The percent operator (\c '%' ) is used do feed parameter values
|
||||
* to be included into the formatted result, at the positions marked
|
||||
* by printf-style placeholders within the format string.
|
||||
* to be included into the formatted result, at the positions marked
|
||||
* by printf-style placeholders within the format string.
|
||||
*
|
||||
* \par type specific treatment
|
||||
* Basic types (numbers, chars, strings) are passed to the implementation
|
||||
|
|
@ -236,49 +236,47 @@ namespace util {
|
|||
|
||||
namespace { // helpers to pick a suitable specialisation....
|
||||
|
||||
/**
|
||||
* by default we don't allow to
|
||||
using std::__and_;
|
||||
using std::__not_;
|
||||
|
||||
/**
|
||||
* by default we don't allow to
|
||||
* treat any types directly by boost::format.
|
||||
* As fallback we rather just produce a type-ID
|
||||
*/
|
||||
template<typename X>
|
||||
struct _allow_call { enum{ value = false };};
|
||||
struct _allow_call : std::false_type {};
|
||||
|
||||
/* the following definitions enable some primitive types
|
||||
* to be handed over to the boost::format implementation */
|
||||
template<> struct _allow_call<string> { enum{ value = true }; };
|
||||
template<> struct _allow_call<char> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uchar> { enum{ value = true }; };
|
||||
template<> struct _allow_call<int16_t> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uint16_t>{ enum{ value = true }; };
|
||||
template<> struct _allow_call<int32_t> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uint32_t>{ enum{ value = true }; };
|
||||
template<> struct _allow_call<int64_t> { enum{ value = true }; };
|
||||
template<> struct _allow_call<uint64_t>{ enum{ value = true }; };
|
||||
template<> struct _allow_call<float> { enum{ value = true }; };
|
||||
template<> struct _allow_call<double> { enum{ value = true }; };
|
||||
template<> struct _allow_call<string> : std::true_type { };
|
||||
template<> struct _allow_call<char> : std::true_type { };
|
||||
template<> struct _allow_call<uchar> : std::true_type { };
|
||||
template<> struct _allow_call<int16_t> : std::true_type { };
|
||||
template<> struct _allow_call<uint16_t>: std::true_type { };
|
||||
template<> struct _allow_call<int32_t> : std::true_type { };
|
||||
template<> struct _allow_call<uint32_t>: std::true_type { };
|
||||
template<> struct _allow_call<int64_t> : std::true_type { };
|
||||
template<> struct _allow_call<uint64_t>: std::true_type { };
|
||||
template<> struct _allow_call<float> : std::true_type { };
|
||||
template<> struct _allow_call<double> : std::true_type { };
|
||||
#ifndef __x86_64__
|
||||
template<> struct _allow_call<long> { enum{ value = true }; };
|
||||
template<> struct _allow_call<ulong> { enum{ value = true }; };
|
||||
template<> struct _allow_call<long> : std::true_type { };
|
||||
template<> struct _allow_call<ulong> : std::true_type { };
|
||||
#endif
|
||||
|
||||
template<typename X>
|
||||
struct _shall_format_directly
|
||||
{
|
||||
typedef typename lib::meta::UnConst<X>::Type BaseType;
|
||||
|
||||
enum{ value = _allow_call<BaseType>::value };
|
||||
};
|
||||
|
||||
|
||||
: _allow_call<std::remove_cv_t<X>>
|
||||
{ };
|
||||
|
||||
template<typename X>
|
||||
struct _shall_convert_toString
|
||||
{
|
||||
enum{ value = not _shall_format_directly<X>::value
|
||||
and lib::meta::can_convertToString<X>::value
|
||||
};
|
||||
};
|
||||
: __and_<__not_<_shall_format_directly<X>>
|
||||
, std::bool_constant<lib::meta::can_convertToString<X>::value>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
template<typename SP>
|
||||
struct _is_smart_wrapper
|
||||
|
|
@ -297,12 +295,10 @@ namespace util {
|
|||
|
||||
template<typename SP>
|
||||
struct _shall_show_smartWrapper
|
||||
{
|
||||
enum{ value = not _shall_convert_toString<SP>::value
|
||||
and _is_smart_wrapper<typename std::remove_reference<
|
||||
typename std::remove_cv<SP>::type>::type>::value
|
||||
};
|
||||
};
|
||||
: __and_<__not_<_shall_convert_toString<SP>>
|
||||
,_is_smart_wrapper<std::remove_reference_t<std::remove_cv_t<SP>>>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
|
@ -426,7 +422,7 @@ namespace util {
|
|||
static void
|
||||
dump (VAL const& val, Implementation& impl)
|
||||
try {
|
||||
format (string(val), impl);
|
||||
format (string(val), impl);
|
||||
}
|
||||
catch(std::exception const& ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -342,11 +342,18 @@ namespace lib {
|
|||
using meta::_Fun;
|
||||
using std::__and_;
|
||||
using std::__not_;
|
||||
using std::is_const_v;
|
||||
using std::is_base_of;
|
||||
using std::common_type;
|
||||
using std::common_type_t;
|
||||
using std::conditional_t;
|
||||
using std::is_convertible;
|
||||
using std::remove_reference_t;
|
||||
using meta::can_IterForEach;
|
||||
using meta::can_STL_ForEach;
|
||||
using meta::ValueTypeBinding;
|
||||
using meta::has_TypeResult;
|
||||
|
||||
|
||||
META_DETECT_FUNCTION_ARGLESS(checkPoint);
|
||||
META_DETECT_FUNCTION_ARGLESS(iterNext);
|
||||
|
|
@ -441,6 +448,38 @@ namespace lib {
|
|||
: _DecoratorTraits<ISO*>
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* helper to derive a suitable common type when expanding children
|
||||
* @tparam SRC source iterator fed into the Expander
|
||||
* @tparam RES result type of the expansion function
|
||||
*/
|
||||
template<class SRC, class RES>
|
||||
struct _ExpanderTraits
|
||||
{
|
||||
using ResIter = typename _DecoratorTraits<RES>::SrcIter;
|
||||
using SrcYield = typename ValueTypeBinding<SRC>::value_type;
|
||||
using ResYield = typename ValueTypeBinding<ResIter>::value_type;
|
||||
static constexpr bool can_reconcile =
|
||||
has_TypeResult<common_type<SrcYield,ResYield>>();
|
||||
|
||||
static_assert (can_reconcile,
|
||||
"source iterator and result from the expansion must yield compatible values");
|
||||
static_assert (is_const_v<SrcYield> == is_const_v<ResYield>,
|
||||
"source and expanded types differ in const-ness");
|
||||
|
||||
// NOTE: unfortunately std::common_type decays (strips cv and reference)
|
||||
// in C++20, there would be std::common_reference; for now we have to work around that
|
||||
using CommonType = conditional_t<is_const_v<SrcYield> or is_const_v<ResYield>
|
||||
, const common_type_t<SrcYield,ResYield>
|
||||
, common_type_t<SrcYield,ResYield>
|
||||
>;
|
||||
using value_type = typename ValueTypeBinding<CommonType>::value_type;
|
||||
using reference = typename ValueTypeBinding<CommonType>::reference;
|
||||
using pointer = typename ValueTypeBinding<CommonType>::pointer;
|
||||
};
|
||||
|
||||
}//(End) TreeExplorer traits
|
||||
|
||||
|
||||
|
|
@ -628,10 +667,8 @@ namespace lib {
|
|||
{
|
||||
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
|
||||
|
||||
using ResIter = typename _DecoratorTraits<RES>::SrcIter;
|
||||
static_assert (std::is_convertible<typename ResIter::value_type, typename SRC::value_type>(),
|
||||
"the iterator from the expansion must yield compatible values");
|
||||
|
||||
using _Trait = _ExpanderTraits<SRC,RES>;
|
||||
using ResIter = typename _Trait::ResIter;
|
||||
using RootExpandFunctor = function<RES(SRC&)>;
|
||||
using ChldExpandFunctor = function<RES(ResIter&)>;
|
||||
|
||||
|
|
@ -694,6 +731,12 @@ namespace lib {
|
|||
|
||||
public: /* === Iteration control API for IterableDecorator === */
|
||||
|
||||
/** @note result type bindings based on a common type of source and expanded result */
|
||||
using value_type = typename _Trait::value_type;
|
||||
using reference = typename _Trait::reference;
|
||||
using pointer = typename _Trait::pointer;
|
||||
|
||||
|
||||
bool
|
||||
checkPoint() const
|
||||
{
|
||||
|
|
@ -703,7 +746,7 @@ namespace lib {
|
|||
or SRC::isValid();
|
||||
}
|
||||
|
||||
typename SRC::reference
|
||||
reference
|
||||
yield() const
|
||||
{
|
||||
return hasChildren()? **expansions_
|
||||
|
|
|
|||
|
|
@ -666,12 +666,6 @@ namespace lib {
|
|||
return SingleValIter<VAL>{forward<VAL>(something)};
|
||||
}
|
||||
|
||||
template<class VAL>
|
||||
inline auto
|
||||
singleValIterator (VAL const& ref)
|
||||
{
|
||||
return SingleValIter<VAL>{ref};
|
||||
}
|
||||
|
||||
/** not-anything-at-all iterator */
|
||||
template<class VAL>
|
||||
|
|
|
|||
|
|
@ -322,6 +322,14 @@ namespace meta {
|
|||
>
|
||||
{ };
|
||||
|
||||
/** verify the first (special) type can stand-in for the second */
|
||||
template<typename S, typename G>
|
||||
struct can_StandIn
|
||||
: std::is_convertible<typename RefTraits<S>::Reference
|
||||
,typename RefTraits<G>::Reference
|
||||
>
|
||||
{ };
|
||||
|
||||
/** detect various flavours of string / text data */
|
||||
template<typename X>
|
||||
struct is_StringLike
|
||||
|
|
|
|||
|
|
@ -106,6 +106,35 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* @internal helper to detect a nested field `TY::type` or `TY::Type.
|
||||
* @remark need to use this indirect detection method, since some of the
|
||||
* type traits from the standard library (notably `std::common_type`)
|
||||
* use a multiple layer deep indirect definition, which fails to be selected
|
||||
* on a simple direct template specialisation.
|
||||
*/
|
||||
template<typename TY>
|
||||
class _DetectNested_TypeResult
|
||||
{
|
||||
template<class ZZ>
|
||||
static Yes_t check(typename ZZ::type *);
|
||||
template<class X>
|
||||
static Yes_t check(typename X::Type *);
|
||||
template<class>
|
||||
static No_t check(...);
|
||||
|
||||
public:
|
||||
static const bool value = (sizeof(Yes_t)==sizeof(check<TY>(0)));
|
||||
};
|
||||
|
||||
}
|
||||
/** helper to check if another metafunction produced a result type */
|
||||
template<typename X>
|
||||
struct has_TypeResult : std::bool_constant<_DetectNested_TypeResult<X>::value> { };
|
||||
|
||||
|
||||
|
||||
/** detect possibility of a conversion to string.
|
||||
* Naive implementation, which first attempts to build a string instance by
|
||||
* implicit conversion, and then tries to invoke an explicit string conversion.
|
||||
|
|
@ -141,35 +170,6 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
/** strip const from type: naive implementation */
|
||||
template<typename T>
|
||||
struct UnConst
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct UnConst<const T>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<const T *>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<T * const>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
template<typename T>
|
||||
struct UnConst<const T * const>
|
||||
{
|
||||
typedef T* Type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Trait template for detecting a typelist type.
|
||||
* For example, this allows to write specialisations
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ namespace wrapper {
|
|||
class ItemWrapper
|
||||
{
|
||||
|
||||
using TY_unconst = typename meta::UnConst<TY>::Type ;
|
||||
using TY_unconst = std::remove_const_t<TY>;
|
||||
|
||||
|
||||
mutable
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "lib/util.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/meta/duck-detector.hpp"///////////////TODO WIP
|
||||
|
||||
using test::Test;
|
||||
|
||||
|
|
@ -43,6 +44,8 @@ namespace lib {
|
|||
namespace iter_explorer {
|
||||
template<class RES>
|
||||
using DecoTraits = _DecoratorTraits<RES>;
|
||||
template<class SRC, class RES>
|
||||
using ExpoTraits = _ExpanderTraits<SRC,RES>;
|
||||
}}
|
||||
///////////////////////////////////////////////////////TODO WIP for investigation
|
||||
namespace steam {
|
||||
|
|
@ -55,6 +58,41 @@ namespace test {
|
|||
using util::isSameObject;
|
||||
using util::seqTuple;
|
||||
|
||||
///////////////////////////////////////////////////////TODO WIP for investigation
|
||||
template<class U>
|
||||
struct ReBind
|
||||
{
|
||||
using type = typename U::type;
|
||||
};
|
||||
// template<typename X, typename SEL = void>
|
||||
// struct has_TypeResult : std::false_type { };
|
||||
//
|
||||
// template<typename X>
|
||||
// struct has_TypeResult<X, typename ReBind<X>::type> : std::true_type { };
|
||||
//
|
||||
// template<typename X>
|
||||
// struct has_TypeResult<X, typename X::Type> : std::true_type { };
|
||||
|
||||
// using lib::meta::Yes_t;
|
||||
// using lib::meta::No_t;
|
||||
//
|
||||
// template<typename TY>
|
||||
// class HasNested_type
|
||||
// {
|
||||
// template<class X>
|
||||
// static Yes_t check(typename X::type *);
|
||||
// template<class X>
|
||||
// static Yes_t check(typename X::Type *);
|
||||
// template<class>
|
||||
// static No_t check(...);
|
||||
//
|
||||
// public:
|
||||
// static const bool value = (sizeof(Yes_t)==sizeof(check<TY>(0)));
|
||||
// };
|
||||
//
|
||||
// template<typename X>
|
||||
// struct has_TypeResult : std::bool_constant<HasNested_type<X>::value> { };
|
||||
///////////////////////////////////////////////////////TODO WIP for investigation
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -350,30 +388,31 @@ namespace test {
|
|||
.genNode()};
|
||||
|
||||
using RTick = std::reference_wrapper<JobTicket>;
|
||||
auto start = singleValIterator (& util::unConst(mockSegs[Time::ZERO].jobTicket()));
|
||||
auto start = singleValIterator (mockSegs[Time::ZERO].jobTicket());
|
||||
|
||||
using SrC = lib::iter_explorer::BaseAdapter<lib::SingleValIter<engine::JobTicket*> >;
|
||||
using SrC = lib::iter_explorer::BaseAdapter<lib::SingleValIter<engine::JobTicket const&> >;
|
||||
|
||||
auto bunny = [](JobTicket* ticket)
|
||||
auto bunny = [](JobTicket const& ticket)
|
||||
{
|
||||
return lib::transformIterator(ticket->getPrerequisites()
|
||||
,[](JobTicket const& preq) -> JobTicket*
|
||||
{ return unConst(&preq); }
|
||||
);
|
||||
return ticket.getPrerequisites();
|
||||
// return lib::transformIterator(ticket.getPrerequisites()
|
||||
// ,[](JobTicket const& preq) -> JobTicket*
|
||||
// { return unConst(&preq); }
|
||||
// );
|
||||
};
|
||||
using ExIt = decltype(bunny(std::declval<JobTicket*>()));
|
||||
// ergibt: lib::TransformIter<lib::TransformIter<lib::IterStateWrapper<steam::engine::JobTicket::Prerequisite, lib::LinkedElements<steam::engine::JobTicket::Prerequisite>::IterationState>, const steam::engine::JobTicket&>, steam::engine::JobTicket*>
|
||||
using ExIt = decltype(bunny(std::declval<JobTicket const&>()));
|
||||
|
||||
using Funny = std::function<ExIt(JobTicket*)>;
|
||||
using Funny = std::function<ExIt(JobTicket const&)>;
|
||||
Funny funny = bunny;
|
||||
|
||||
using ExpandedChildren = typename lib::iter_explorer::_FunTraits<Funny,SrC>::Res;
|
||||
|
||||
|
||||
using ResIter = typename lib::iter_explorer::DecoTraits<ExpandedChildren>::SrcIter;
|
||||
// lib::test::TypeDebugger<ResIter> buggy;
|
||||
using ResIterVal = typename ResIter::value_type;
|
||||
using SrcIterVal = typename SrC::value_type;
|
||||
//lib::test::TypeDebugger<ResIterVal> buggy;
|
||||
// lib::test::TypeDebugger<ResIterVal> buggy;
|
||||
// lib::test::TypeDebugger<ExIt> bugggy;
|
||||
|
||||
using FunResTrait = lib::iter_explorer::_FunTraits<Funny,ResIter>;
|
||||
|
|
@ -382,8 +421,38 @@ namespace test {
|
|||
static_assert(std::is_convertible<typename ResIter::reference, FunArg>());
|
||||
// lib::test::TypeDebugger<decltype(ArgAdaptRes::wrap(bunny))> buggy;
|
||||
|
||||
// using ResCore = iter_explorer::Expander<SRC, ExpandedChildren>;
|
||||
using ResCore = lib::iter_explorer::Expander<SrC, ExpandedChildren>;
|
||||
|
||||
// using ExResIter = typename lib::iter_explorer::DecoTraits<ResCore>::SrcIter;
|
||||
// static_assert(lib::meta::can_IterForEach<ResCore>::value);
|
||||
// static_assert(lib::meta::can_STL_ForEach<ResCore>::value);
|
||||
struct Murks
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
struct Gurks : Murks { };
|
||||
static_assert(lib::meta::has_TypeResult<Gurks>());
|
||||
using Wootz = std::common_type<JobTicket&, JobTicket const&>;
|
||||
using Wauzz = typename Wootz::type;
|
||||
// lib::test::TypeDebugger<Wauzz> bully;
|
||||
|
||||
static_assert(lib::meta::has_TypeResult<std::common_type<JobTicket*, void*>>());
|
||||
// static_assert(HasNested_type<Gurks>::value);
|
||||
// static_assert(HasNested_type<Wootz>::value);
|
||||
// static_assert(has_TypeResult<Wootz>());
|
||||
|
||||
using ExiTrait = lib::iter_explorer::ExpoTraits<SrC, ExpandedChildren>;
|
||||
using WrapIter = typename lib::iter_explorer::DecoTraits<ResCore>::SrcIter;
|
||||
// lib::test::TypeDebugger<typename lib::meta::ValueTypeBinding<WrapIter>::reference> bully;
|
||||
// static_assert(std::is_const_v<JobTicket const&>);
|
||||
// static_assert(std::is_const_v<JobTicket const>);
|
||||
// static_assert(std::is_const_v<JobTicket&&>);
|
||||
// lib::test::TypeDebugger<std::common_type_t<JobTicket const, JobTicket const>> bully;
|
||||
// lib::test::TypeDebugger<typename ExiTrait::CommonType> bully;
|
||||
// lib::test::TypeDebugger<typename ExiTrait::reference> bully;
|
||||
// lib::test::TypeDebugger<ResCore::reference> bully;
|
||||
|
||||
|
||||
auto it = lib::explore(start)
|
||||
// .transform ([](RTick t) -> JobTicket const&
|
||||
|
|
@ -392,9 +461,9 @@ namespace test {
|
|||
// })
|
||||
.expand (funny)
|
||||
.expandAll()
|
||||
.transform ([&](JobTicket * ticket)
|
||||
.transform ([&](JobTicket const& ticket)
|
||||
{
|
||||
return ticket->createJobFor(coord).parameter.invoKey.part.a;
|
||||
return ticket.createJobFor(coord).parameter.invoKey.part.a;
|
||||
});
|
||||
cout << util::join(it,"-") <<endl;
|
||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1294
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/builder-qualifier-support.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -117,19 +118,19 @@ namespace test{
|
|||
run (Arg)
|
||||
{
|
||||
ExampleStrategy f0;
|
||||
CHECK ("Strategy{∅}" == string(f0));
|
||||
CHECK (f0 == "Strategy{∅}"_expect);
|
||||
|
||||
ExampleStrategy f1(one());
|
||||
CHECK ("Strategy{!one!}" == string(f1));
|
||||
CHECK (f1 == "Strategy{!one!}"_expect);
|
||||
|
||||
ExampleStrategy f2(two("Ψ"));
|
||||
CHECK ("Strategy{∅.two(Ψ)}" == string(f2));
|
||||
CHECK (f2 == "Strategy{∅.two(Ψ)}"_expect);
|
||||
|
||||
ExampleStrategy f3(one(), two("↯"));
|
||||
CHECK ("Strategy{!one!.two(↯)}" == string(f3));
|
||||
CHECK (f3 == "Strategy{!one!.two(↯)}"_expect);
|
||||
|
||||
ExampleStrategy f4(two("☭"), one());
|
||||
CHECK ("Strategy{!one!}" == string(f4)); // Note: evaluated from left to right, one() overwrites prop_
|
||||
CHECK (f4 == "Strategy{!one!}"_expect); // Note: evaluated from left to right, one() overwrites prop_
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -70464,6 +70464,11 @@
|
|||
</html></richcontent>
|
||||
<linktarget COLOR="#a9b4c1" DESTINATION="ID_247789540" ENDARROW="Default" ENDINCLINATION="-15;-42;" ID="Arrow_ID_830127139" SOURCE="ID_672540161" STARTARROW="None" STARTINCLINATION="-53;2;"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1684718878713" ID="ID_741543772" MODIFIED="1684719029190" TEXT="Aber: rein-technisch kann es dabei zu Problemen kommen">
|
||||
<arrowlink COLOR="#a0366c" DESTINATION="ID_368029592" ENDARROW="Default" ENDINCLINATION="-353;-1260;" ID="Arrow_ID_1815839573" STARTARROW="None" STARTINCLINATION="-394;19;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1684718925338" ID="ID_917570391" MODIFIED="1684718961903" TEXT=""Konversion" kann man nur testen, indem man zuweist oder konstruiert"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1684199691017" HGAP="11" ID="ID_791332898" MODIFIED="1684199727372" TEXT="was die Itertools bisher machen ist eindeutig falsch" VSHIFT="25">
|
||||
|
|
@ -71257,6 +71262,263 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1684712494897" ID="ID_1651369451" MODIFIED="1684712520817" TEXT="nun die Pipeline auch noch mit Referenzen verwendbar machen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1684714660497" ID="ID_216562837" MODIFIED="1684714672132" TEXT="mit JobTicket const&"/>
|
||||
<node COLOR="#435e98" CREATED="1684714672777" ID="ID_1009372749" MODIFIED="1684714888355" TEXT="Problem mit singleValIterator">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1684714690142" ID="ID_1957543134" MODIFIED="1684714710351" TEXT="can const& nicht per »perfect forwarding« weitergeben..."/>
|
||||
<node COLOR="#690f14" CREATED="1684714711059" ID="ID_967208436" MODIFIED="1684714776321" TEXT="wer macht denn auch sowas???">
|
||||
<icon BUILTIN="closed"/>
|
||||
<node CREATED="1684714743215" ID="ID_814301239" MODIFIED="1684714756026" TEXT="perfect forwarding allein genügt"/>
|
||||
<node CREATED="1684714756619" ID="ID_1346128339" MODIFIED="1684714763268" TEXT="genau deshalb haben wir es ja">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1684714845060" ID="ID_604591501" MODIFIED="1684714883880" TEXT="überprüft: ItermWraper sollte problemlos auch mit const& und const-values umgehen können">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684714724138" ID="ID_313083920" MODIFIED="1684714885761" TEXT="da war von Anfang an ein unsinniger Overload definiert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
möglicherweise hat damals (2017) das <i>perfect forwarding</i> noch nicht so gut funktioniert (wir verwenden ja debian/stable, das war dann von 2015 und hatte noch etwas ältere Compiler)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1684714892122" ID="ID_329151858" MODIFIED="1684796083945" TEXT="nun triggert wieder die 1. Assertion">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1684714917783" ID="ID_1666247735" MODIFIED="1684714918845" TEXT="iterator from the expansion must yield compatible values"/>
|
||||
<node CREATED="1684714923061" ID="ID_383268607" MODIFIED="1684714930177" TEXT="also wieder die Typen analyiseren">
|
||||
<node CREATED="1684714946435" ID="ID_334603007" MODIFIED="1684715091724" TEXT="SRC::value_type ≡ const JobTicket"/>
|
||||
<node CREATED="1684715584636" ID="ID_76173507" MODIFIED="1684715618419" TEXT="ResIter::value_type ≡ const JobTicket"/>
|
||||
<node COLOR="#653fa0" CREATED="1684715619286" ID="ID_904849887" MODIFIED="1684715630403" TEXT="???wtf">
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1684715638340" ID="ID_1365358435" MODIFIED="1684715658748" TEXT="hier tut sich wieder dieser sonderbare Seitenzweig der Auswertung auf">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1684716149222" ID="ID_1129612900" MODIFIED="1684716155410" TEXT="Beobachtungen">
|
||||
<node CREATED="1684715758343" ID="ID_172131299" MODIFIED="1684716173203" TEXT="es passiert also nun eine Ebene höher (in der expand()-Funktion)"/>
|
||||
<node COLOR="#435e98" CREATED="1684716157636" ID="ID_1561245265" MODIFIED="1684717262236" TEXT="warum gehen wir in enable_if<shall_wrap_STL_Iter<SRC>>">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1684717043510" ID="ID_1400705695" MODIFIED="1684717070089" TEXT="vermutlich „gehen wir“ da gar nicht rein..."/>
|
||||
<node CREATED="1684717070725" ID="ID_121719490" MODIFIED="1684717089749" TEXT="sondern der Compiler muß alle Alterativen Spezialisierungen instantiieren"/>
|
||||
<node CREATED="1684717090466" ID="ID_1403746724" MODIFIED="1684717114554" TEXT="und der can_STL_ForEach<Expander> greift auf Expander::iterator zu"/>
|
||||
<node CREATED="1684717115467" ID="ID_262814818" MODIFIED="1684717136990" TEXT="...und deshalb muß der Compiler an der stelle den Typ "Expander" vollständig instantiieren"/>
|
||||
<node CREATED="1684717200092" ID="ID_98622165" MODIFIED="1684717208077" TEXT="geprüft...">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1684717209567" ID="ID_446917707" MODIFIED="1684717230204" TEXT="static_assert(lib::meta::can_IterForEach<ResCore>::value); ⟶ OK"/>
|
||||
<node CREATED="1684717209568" ID="ID_66269810" MODIFIED="1684717235771" TEXT="static_assert(lib::meta::can_STL_ForEach<ResCore>::value); ⟶ scheitert"/>
|
||||
<node COLOR="#338800" CREATED="1684717240318" ID="ID_1718285675" MODIFIED="1684717243638" TEXT="so soll es sein">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1684717669978" ID="ID_744382124" MODIFIED="1684717705255">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
HA!  std::is_convertible<const JobTicket, const JobTicket>()  ⟶ <b><font color="#ec1f1f">false</font></b>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1684718697838" ID="ID_602944557" LINK="https://en.cppreference.com/w/cpp/types/is_convertible" MODIFIED="1684718723602" TEXT="Doku lesen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1684718732856" ID="ID_1157631148" MODIFIED="1684718738269" TEXT="JobTicket test() { return std::declval<JobTicket>(); }"/>
|
||||
<node CREATED="1684718752670" ID="ID_890763633" MODIFIED="1684718800585" TEXT="error: use of deleted function 'JobTicket::JobTicket(JobTicket&&)"/>
|
||||
<node CREATED="1684718803063" ID="ID_661035421" MODIFIED="1684718815493" TEXT="denn JobTicket ist non-copyable">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684718826468" ID="ID_368029592" MODIFIED="1684796105008" TEXT="also doch: besserer Test für »kompatible Werte« gesucht">
|
||||
<linktarget COLOR="#a0366c" DESTINATION="ID_368029592" ENDARROW="Default" ENDINCLINATION="-353;-1260;" ID="Arrow_ID_1815839573" SOURCE="ID_741543772" STARTARROW="None" STARTINCLINATION="-394;19;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#5b280f" CREATED="1684719111734" ID="ID_1888723433" MODIFIED="1684768943114" TEXT="explizit das »can stand-in« prüfen">
|
||||
<icon BUILTIN="idea"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1684768973732" ID="ID_352142303" MODIFIED="1684768989706" TEXT="das könnte man implementieren per Referenz-Zuweisung"/>
|
||||
<node COLOR="#435e98" CREATED="1684768990580" ID="ID_289921899" MODIFIED="1684796058909" TEXT="müßte dann aber (wenn schon) auch symmetrisch gemacht werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
denn es ist letztlich egal, welcher Typ für welchen eintritt
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1684768944997" ID="ID_1112757073" MODIFIED="1684782022965" TEXT="noch besser: std::common_type<T,U> nutzen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1684782029022" ID="ID_1755897416" MODIFIED="1684782061671">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<b>nein</b>! das Muster <i>ist nicht symmetrisch</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="closed"/>
|
||||
<node CREATED="1684782073847" ID="ID_1123149907" MODIFIED="1684782097872" TEXT="und zwar muß die Expand-Funktion auch ihre eigenen Resultate verarbeiten können"/>
|
||||
<node CREATED="1684782099155" ID="ID_646129307" MODIFIED="1684782122002" TEXT="und außerdem auch die Werte vom Src-Iterator"/>
|
||||
</node>
|
||||
<node CREATED="1684782300304" ID="ID_236176565" MODIFIED="1684796071420" TEXT="vielmehr müssen sie kreuzweise füreinander stehen können">
|
||||
<arrowlink COLOR="#516980" DESTINATION="ID_1446929219" ENDARROW="Default" ENDINCLINATION="215;-7;" ID="Arrow_ID_721235932" STARTARROW="None" STARTINCLINATION="-180;9;"/>
|
||||
<node CREATED="1684782319772" ID="ID_1923233746" MODIFIED="1684782601445" TEXT="denn expandierte Ergebnisse werden mit Quell-Ergebnissen gemischt">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
was bedeutet, das Ergebnis muß ein gemeinsamer Schnitt-Typ von beiden sein
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1684782387453" ID="ID_1534599276" MODIFIED="1684782557960" TEXT="und expandierte Ergebnisse werden dann wiederum in den Expand-Funktor gefüttert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
und das bedeutet, daß beide Ergebnistypen einen gemeinsamen Schnitt-Typ haben müssen, der auf den Argumenttyp des Expand-Funktors konvertierbar ist
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684769047612" ID="ID_838898432" MODIFIED="1684789425825" TEXT="trotzdem auch das can_StandIn implementieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684789434831" ID="ID_1446929219" MODIFIED="1684796064539" TEXT="bessere Lösung: beide Typen auf einen gemeinsamen Typ vereinigen">
|
||||
<linktarget COLOR="#516980" DESTINATION="ID_1446929219" ENDARROW="Default" ENDINCLINATION="215;-7;" ID="Arrow_ID_721235932" SOURCE="ID_236176565" STARTARROW="None" STARTINCLINATION="-180;9;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1684789534660" ID="ID_694264595" MODIFIED="1684789555569" TEXT="oh das wird komplex....">
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
<node COLOR="#338800" CREATED="1684789574535" ID="ID_316752857" MODIFIED="1684790067988" TEXT="Nebenproblem: sollte eine static-Assertion mit einbauen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1684789594748" ID="ID_1799454021" MODIFIED="1684789631192" TEXT="aber leider läßt sich std::common_type<T,U> nicht direkt ⟼ bool prüfen">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684789632511" ID="ID_166021610" MODIFIED="1684790058387" TEXT="Hilfs-Template in meta/util.hpp">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1684789645555" ID="ID_72793797" MODIFIED="1684790061401" TEXT="Problem: direkte Template-Spezialisierung funktioniert nicht">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
ist vielleicht sogar ein Compiler-Bug?
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
zwar hat std::common_type definitiv eine nested Typedef
|
||||
</li>
|
||||
<li>
|
||||
aber diese wird relativ indirekt erzeugt, über den decltype einer Check-Funktion im Basis-Helper
|
||||
</li>
|
||||
<li>
|
||||
und eine einfache Template-Spezialisierung wird matcht darauf nicht
|
||||
</li>
|
||||
<li>
|
||||
obwohl die gleiche Technik bei einer einfachen Struct funktioniert (selbst bei Vererbung)
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684789660347" ID="ID_1197665422" MODIFIED="1684789683265" TEXT="dann eine Hilfs-Template nach dem "duck-detector"-Baumuster verwenden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1684789563585" ID="ID_901412607" MODIFIED="1684790633745" TEXT="brauche dann wohl ein verschachteltes Trait-Template">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1684790408327" ID="ID_321137337" MODIFIED="1684790417923" TEXT="dann könnte man sogar die beiden Fuktoren wegpacken"/>
|
||||
<node CREATED="1684790380788" ID="ID_901065738" MODIFIED="1684790407118" TEXT="nein...">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node CREATED="1684790392235" ID="ID_1037155961" MODIFIED="1684790630471" TEXT="das macht es nur undurchsichtiger">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und zwar weil eben auch der IterStack mit involviert ist, und die State-Core-Implementierungs-Funktionen allesamt verzweigen, je nachdem ob schon expandierte Kinder da sind; es bringt nichts, diese Verzweigungs-Struktur irgendwo wegzupacken, entweder man zerreißt sie in zwei Teile (wodurch sie unverständlich wird), oder der Expander selber wird eine leere Hülle, und alle Logik wandert in ein Delegate (wozu das?)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684790081801" ID="ID_1718594831" MODIFIED="1684796053717" TEXT="Implementierung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1684790647174" ID="ID_1207401632" MODIFIED="1684790663368" TEXT="nachdem ich mehrere Stunden herumgekonobelt habe....">
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684790665445" ID="ID_411175859" MODIFIED="1684796044584" TEXT="eine verbesserte Assertion">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1684790815465" ID="ID_517001911" MODIFIED="1684790830587" TEXT="nur diese allein könnte man in ein Trait-Template auslagern"/>
|
||||
<node CREATED="1684790831558" ID="ID_1842116648" MODIFIED="1684790846059" TEXT="damit verschwinden technische Details">
|
||||
<node CREATED="1684794221414" ID="ID_1312364680" MODIFIED="1684794229388" TEXT="rebinding über common_type"/>
|
||||
<node COLOR="#435e98" CREATED="1684794229976" ID="ID_1893749402" MODIFIED="1684796036589" TEXT="Problem: common_type entfernt cv und referenzen">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1684794301957" ID="ID_1686570526" MODIFIED="1684794321433" TEXT="in C++20 gäbe es common_reference_t">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684794311174" ID="ID_1882627403" MODIFIED="1684796038475" TEXT="also darum herumarbeiten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1684790847496" ID="ID_93335409" MODIFIED="1684790912014" TEXT="und man kann notfalls das Trait-Template isoliert debuggen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...das hat sich nun schon mehrfach als sehr hilfreich erwiesen: man instantiiert das Trait-Template „auf der grünnen Wiese“ und kann es dann direkt mit lib::test::TypeDebugger analysieren...
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1684790699401" ID="ID_455599839" MODIFIED="1684796046584" TEXT="und nested type-defs aufbauen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1684790716001" ID="ID_1920868863" MODIFIED="1684796052395" TEXT="sonst besser alles autmatisch laufen lassen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue