Library: investigate malfunction in metaprogramming
the template lib::PolymorphicValue seemingly picked the wrong implementation strategy for "virtual copy support": In fact it is possible to use the optimal strategy here, since our interface inherits from CloneSupport, yet the metaprogramming logic picked the mix-in-adapter (which requires one additional "slot" of storage plus a dynamic_cast at runtime). The reason for this malfunction was the fact that we used META_DETECT_FUNCTION to detect the presence of a clone-support-function. This is not correct, since it can only detect a function in the *same* class, not an inherited function. Thus, switching to META_DETECT_FUNCTION_NAME solves this problem Well, this solution has some downsides, but since I intend to rewrite the whole virtual copy support (#1197) anyway, I'll deem this acceptable for now TODO / WIP: still some diagnostics code to clean up, plus a better solution for the EmptyBase
This commit is contained in:
parent
23c9da7c62
commit
8f43c2591e
5 changed files with 172 additions and 10 deletions
|
|
@ -244,6 +244,12 @@ applyTuple (FUN& fun)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using lib::meta::Yes_t;
|
||||||
|
using lib::meta::No_t;
|
||||||
|
|
||||||
|
META_DETECT_FUNCTION(void, cloneInto, (void*) const);
|
||||||
|
META_DETECT_FUNCTION_NAME(cloneInto);
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int, char**)
|
main (int, char**)
|
||||||
|
|
@ -275,6 +281,19 @@ main (int, char**)
|
||||||
// recy.grrrn (std::get<0>(trp), Trackr(5));
|
// recy.grrrn (std::get<0>(trp), Trackr(5));
|
||||||
holyh.applyTo (recy);
|
holyh.applyTo (recy);
|
||||||
|
|
||||||
|
cout << "---Types---"<<endl;
|
||||||
|
using BussI = lib::VerbInvoker<Receiver, void>;
|
||||||
|
using CloneI = lib::polyvalue::CloneValueSupport<lib::polyvalue::EmptyBase>;
|
||||||
|
SHOW_TYPE(BussI);
|
||||||
|
SHOW_EXPR (lib::polyvalue::exposes_CloneFunction<BussI>::value)
|
||||||
|
SHOW_EXPR (HasFunSig_cloneInto<BussI>::value)
|
||||||
|
SHOW_EXPR (HasFunSig_cloneInto<CloneI>::value)
|
||||||
|
SHOW_EXPR (HasFunName_cloneInto<BussI>::value)
|
||||||
|
SHOW_EXPR (HasFunName_cloneInto<CloneI>::value)
|
||||||
|
using BussP = decltype(&BussI::cloneInto);
|
||||||
|
SHOW_TYPE(BussP)
|
||||||
|
|
||||||
|
|
||||||
cout << "\n.gulp.\n";
|
cout << "\n.gulp.\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@
|
||||||
** Moreover, the PolymorphicValue container provides static builder functions,
|
** Moreover, the PolymorphicValue container provides static builder functions,
|
||||||
** allowing to place a concrete instance of a subclass into the content buffer.
|
** allowing to place a concrete instance of a subclass into the content buffer.
|
||||||
** After construction, the actual type of this instance will be forgotten
|
** After construction, the actual type of this instance will be forgotten
|
||||||
** (``type erasure''), but because of the embedded vtable, on access the
|
** (``type erasure''), but because of the embedded vtable, on access, the
|
||||||
** proper implementation functions will be invoked.
|
** proper implementation functions will be invoked.
|
||||||
**
|
**
|
||||||
** Expanding on that pattern, the copying and cloning operations of the whole
|
** Expanding on that pattern, the copying and cloning operations of the whole
|
||||||
|
|
@ -230,11 +230,11 @@ namespace lib {
|
||||||
class exposes_CloneFunction
|
class exposes_CloneFunction
|
||||||
{
|
{
|
||||||
|
|
||||||
META_DETECT_FUNCTION(void, cloneInto, (void*) const);
|
META_DETECT_FUNCTION_NAME(cloneInto);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum{ value = HasFunSig_cloneInto<T>::value
|
enum{ value = HasFunName_cloneInto<T>::value
|
||||||
};
|
}; // warning: match on the function name only
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -373,7 +373,7 @@ namespace lib {
|
||||||
>
|
>
|
||||||
class PolymorphicValue
|
class PolymorphicValue
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
typedef polyvalue::Trait<CPY> _Traits;
|
typedef polyvalue::Trait<CPY> _Traits;
|
||||||
typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
|
typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
|
||||||
typedef typename _Traits::Assignment _AssignmentPolicy; /////////////////TICKET #1197 : confusingly indirect decision logic
|
typedef typename _Traits::Assignment _AssignmentPolicy; /////////////////TICKET #1197 : confusingly indirect decision logic
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,11 @@ namespace lib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using EmptyBasE = struct { };
|
||||||
|
|
||||||
template<class REC, class RET>
|
template<class REC, class RET>
|
||||||
struct VerbInvoker
|
struct VerbInvoker
|
||||||
: polyvalue::CloneValueSupport<polyvalue::EmptyBase> // mark and mix-in virtual copy construction support
|
: polyvalue::CloneValueSupport<EmptyBasE> // mark and mix-in virtual copy construction support
|
||||||
{
|
{
|
||||||
virtual ~VerbInvoker() { }
|
virtual ~VerbInvoker() { }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,10 @@ namespace test{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SHOW_TYPE(_TY_) \
|
||||||
|
cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() <<endl;
|
||||||
|
#define SHOW_EXPR(_XX_) \
|
||||||
|
cout << "Probe " << STRINGIFY(_XX_) << " ? = " << _XX_ <<endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -151,6 +155,22 @@ namespace test{
|
||||||
TokenSeq tokens = build_and_copy_tokens();
|
TokenSeq tokens = build_and_copy_tokens();
|
||||||
render_verbose (tokens);
|
render_verbose (tokens);
|
||||||
// profile.append_woof(1, 2);
|
// profile.append_woof(1, 2);
|
||||||
|
|
||||||
|
using IrrelvantType = struct{};
|
||||||
|
const size_t VERB_TOK_SIZE = sizeof(lib::VerbToken<IrrelvantType, void(void)>);
|
||||||
|
using HoldL = Holder<Receiver, string(string)>;
|
||||||
|
const size_t VERB_TOK_SIZ2 = sizeof(HoldL::Verb);
|
||||||
|
const size_t HOLDER_SIZE = sizeof(HoldL);
|
||||||
|
const size_t ARG_TUP_SIZE = sizeof(std::tuple<string>);
|
||||||
|
|
||||||
|
SHOW_EXPR (VERB_TOK_SIZE);
|
||||||
|
SHOW_EXPR (VERB_TOK_SIZ2);
|
||||||
|
SHOW_EXPR (HOLDER_SIZE);
|
||||||
|
SHOW_EXPR (ARG_TUP_SIZE);
|
||||||
|
SHOW_EXPR (sizeof(string));
|
||||||
|
using AdapT = Token::Adapter<HoldL>;
|
||||||
|
SHOW_TYPE (AdapT);
|
||||||
|
SHOW_EXPR (sizeof(AdapT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19971,8 +19971,8 @@
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
<icon BUILTIN="messagebox_warning"/>
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555807646555" ID="ID_84342308" MODIFIED="1555807746266" TEXT="CloneValueSupport nicht (korrekt) erkannt">
|
<node COLOR="#338800" CREATED="1555807646555" ID="ID_84342308" MODIFIED="1557446814390" TEXT="CloneValueSupport nicht (korrekt) erkannt">
|
||||||
<icon BUILTIN="flag-yellow"/>
|
<icon BUILTIN="button_ok"/>
|
||||||
<node CREATED="1555807666086" ID="ID_1670738915" MODIFIED="1555807723294" TEXT="offensichtlich wird die falsche Trait-Variante gewählt">
|
<node CREATED="1555807666086" ID="ID_1670738915" MODIFIED="1555807723294" TEXT="offensichtlich wird die falsche Trait-Variante gewählt">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head>
|
<head>
|
||||||
|
|
@ -19986,15 +19986,136 @@
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1555807724232" ID="ID_1817680115" MODIFIED="1555807744748" TEXT="und das, obwohl ich CloneValueSupport als Basis verwendet habe"/>
|
<node CREATED="1555807724232" ID="ID_1817680115" MODIFIED="1555807744748" TEXT="und das, obwohl ich CloneValueSupport als Basis verwendet habe"/>
|
||||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1555807747713" ID="ID_341140224" MODIFIED="1555807752169" TEXT="aufzuklären">
|
<node CREATED="1557446452899" ID="ID_454930922" MODIFIED="1557446811594" TEXT="META_DETECT_FUNCTION erkennt keine geerbten Methoden">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...denn diese Duck-Detector-Metafunktion bildet den <b>Typ</b> eines Member-Pointers,
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
und dieser Typ enthält explizit den statischen Namen der Klasse, welche die gewünschte Methode trägt.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Und wenn man eine Methode bloß erbt, dann existiert diese Methode, statisch, nur auf der Basisklasse.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Also ist das sogar das korrekte Verhalten.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1557446482447" ID="ID_835188518" MODIFIED="1557446493804" TEXT="Lösung: Duck-Detector für Methoden-Name">
|
||||||
|
<node CREATED="1557446494679" ID="ID_1259664145" MODIFIED="1557446574477" TEXT="verzichtet auf Signatur-Check">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
d.h. wenn zufällig das Interface auch eine Methode CloneInto() enthält, aber mit einer unpassenden Signatur
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1557446561925" ID="ID_1267977919" MODIFIED="1557446571295" TEXT="ist ohnehin keine wirkliche Sicherheit"/>
|
||||||
|
<node CREATED="1557446503084" ID="ID_1518606339" MODIFIED="1557446523133" TEXT="würde ohnehin später beim Compilieren scheitern"/>
|
||||||
|
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1557446627092" ID="ID_805659416" MODIFIED="1557446697850" TEXT="mit #1197 hinfällig">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
weil ich dann explizit ein bestimmtes Basis-Interface verlangen werde,
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
nämlich VirtualCopySupport<IFA>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
das ist auch gut so, zu viel Flexibilität schadet (besonders, wenn man sie dann gar nicht unterstützt)
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||||
|
<icon BUILTIN="yes"/>
|
||||||
|
</node>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1557446881265" ID="ID_743886485" MODIFIED="1557446897772" TEXT="Folgeproblem: ambiguous base class">
|
||||||
|
<icon BUILTIN="clanbomber"/>
|
||||||
|
<node CREATED="1557446902070" ID="ID_1511315997" MODIFIED="1557447072957" TEXT="kommt davon, wenn man mehrfach polyvalue::EmptyBase verwendet">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
weil nämlich der Trait, für den optimalen Fall, ebenfalls die EmptyBase verwendet, um den Mix-In zu deaktivieren.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Leider haben wir dann zweimal die gleiche Basisklasse in beiden Zweigen der multiple inheritance...
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1557446924907" ID="ID_1029661613" MODIFIED="1557446979586" TEXT="...was hier absolut naheliegend ist">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
nämlich immer dann, wenn man tatsächlich den CopySupport oder CloneSupport als Basis des Interfaces verwendet...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
(was ich bisher in der Praxis so noch nie gemacht habe)
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1557447075623" ID="ID_1422873677" MODIFIED="1557447148035" TEXT="dummerweise kann dann der GCC die EmptyBase nicht wegoptimieren">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
...was sich dann in einer Static-Assertion-Failure äußert.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
hab das ganz explizit ausgeknobelt, es fehlt hier genau dieser eine zusätzliche "Slot"
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
<icon BUILTIN="broken-line"/>
|
||||||
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1557447159900" ID="ID_691196423" MODIFIED="1557447167364" TEXT="Lösung: anderen Namen verwenden">
|
||||||
<icon BUILTIN="flag-pink"/>
|
<icon BUILTIN="flag-pink"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1555807305357" ID="ID_1511870599" MODIFIED="1555807322414" TEXT="Plan: PolymorphicValue überarbeiten">
|
</node>
|
||||||
|
<node CREATED="1555807305357" ID="ID_1511870599" MODIFIED="1557446848388" TEXT="Plan: PolymorphicValue überarbeiten">
|
||||||
|
<arrowlink COLOR="#1a64bc" DESTINATION="ID_596556632" ENDARROW="Default" ENDINCLINATION="-129;0;" ID="Arrow_ID_884404467" STARTARROW="None" STARTINCLINATION="-284;0;"/>
|
||||||
<node CREATED="1555807415718" ID="ID_639233049" MODIFIED="1555807439478" TEXT="mit "VirtualCopySupport" von meiner Variant-Implementierung zusammenführen"/>
|
<node CREATED="1555807415718" ID="ID_639233049" MODIFIED="1555807439478" TEXT="mit "VirtualCopySupport" von meiner Variant-Implementierung zusammenführen"/>
|
||||||
<node CREATED="1555807443642" ID="ID_90620144" MODIFIED="1555807458413" TEXT="sollte selbständig erkennen, ob der Zieltyp kopierbar ist"/>
|
<node CREATED="1555807443642" ID="ID_90620144" MODIFIED="1555807458413" TEXT="sollte selbständig erkennen, ob der Zieltyp kopierbar ist"/>
|
||||||
<node CREATED="1555807464657" ID="ID_1089528099" MODIFIED="1555807476065" TEXT="diese meta-Intelligenz sollte komplett in dem Adapter stecken"/>
|
<node CREATED="1555807464657" ID="ID_1089528099" MODIFIED="1555807476065" TEXT="diese meta-Intelligenz sollte komplett in dem Adapter stecken"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1557446611550" ID="ID_596556632" MODIFIED="1557446843936" TEXT="Ticket #1197 : rationalise copy support in PolymorphicValue">
|
||||||
|
<linktarget COLOR="#1a64bc" DESTINATION="ID_596556632" ENDARROW="Default" ENDINCLINATION="-129;0;" ID="Arrow_ID_884404467" SOURCE="ID_1511870599" STARTARROW="None" STARTINCLINATION="-284;0;"/>
|
||||||
|
<icon BUILTIN="flag-yellow"/>
|
||||||
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1555807762543" ID="ID_1645640007" MODIFIED="1555807777516" TEXT="Problem: Puffergröße">
|
<node CREATED="1555807762543" ID="ID_1645640007" MODIFIED="1555807777516" TEXT="Problem: Puffergröße">
|
||||||
<node CREATED="1555807778751" ID="ID_1563586526" MODIFIED="1555807801996" TEXT="PolymorphicValue verlangt, daß man die Puffergröße als Template-Argument definiert"/>
|
<node CREATED="1555807778751" ID="ID_1563586526" MODIFIED="1555807801996" TEXT="PolymorphicValue verlangt, daß man die Puffergröße als Template-Argument definiert"/>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue