Invocation: build a solution to adapt std::array
...which should ''basically work,'' since `std::array` is ''»tuple-like«'' — BUT unfortunately it has a quite distinct template signature which does not fit into the generic scheme of a product type. Obviously we'd need a partial specialisation, but even re-implementing this turns out to be damn hard, because there is no way to generate a builder method with a suitable explicit type signature directly, because such a builder would need to accept precisely N arguments of same type. This leads to a different solution approach: we can introduce an ''adapter type'', which will be layered on top of `std::array` and just expose the proper type signature so that the existing Implementation can handle the array, relying on the tuple-protocol. __Note__: this changeset adds a convenient pretty-printer for `std::array`, based on the same forward-declaration trick employed recently for `lib::Several`. You need to include 'lib/format-util.hpp' to actually use it.
This commit is contained in:
parent
8bb332cc5e
commit
0cad2dacc0
5 changed files with 245 additions and 12 deletions
|
|
@ -15,12 +15,12 @@
|
|||
/** @file format-obj.hpp
|
||||
** Simple functions to represent objects, for debugging and diagnostics.
|
||||
** The helpers provided here are rather commonplace, but written in a way
|
||||
** as to incur only modest header inclusion load. It should be OK to use
|
||||
** these even on widely used interface headers.
|
||||
** to incur only modest header inclusion load. It should be OK to use them
|
||||
** even on interface headers in widespread use.
|
||||
** - util::toString() performs a failsafe to-String conversion, thereby preferring a
|
||||
** built-in conversion operator, falling back to a lexical conversion (boost)
|
||||
** or just a unmangled and simplified type string as default.
|
||||
** - util::typedString() combines this with a always visible type display
|
||||
** or just an unmangled and simplified type string as default.
|
||||
** - util::typedString() combines this with an always visible type display
|
||||
** - lib::meta::demangleCxx() uses the built-in compiler support to translate a mangled
|
||||
** type-ID (as given by `typeid(TY).name()`) into a readable, fully qualified
|
||||
** C++ type name. This is only supported for GNU compatible compilers.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "lib/symbol.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
|
@ -259,5 +260,17 @@ namespace util {
|
|||
}
|
||||
|
||||
|
||||
/** convenient pretty-printer for std::array instances */
|
||||
template<typename T, std::size_t N>
|
||||
struct StringConv<std::array<T,N>>
|
||||
{
|
||||
static std::string
|
||||
invoke (std::array<T,N> const& arr) noexcept
|
||||
{
|
||||
return util::toStringBracket (arr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace util
|
||||
#endif /*LIB_FORMAT_UTIL_H*/
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
|
||||
|
||||
|
|
@ -96,5 +97,91 @@ namespace meta{
|
|||
};
|
||||
|
||||
|
||||
/* ===== adapt array for tuple-like signature ===== */
|
||||
|
||||
template<typename...TTT>
|
||||
struct ArrayAdapt;
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename...TTT>
|
||||
struct AllSame
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
template<typename T1, typename T2, typename...TS>
|
||||
struct AllSame<T1,T2,TS...>
|
||||
: __and_<is_same<T1,T2>
|
||||
,AllSame<T2,TS...>
|
||||
>
|
||||
{ };
|
||||
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct Repeat
|
||||
{
|
||||
using Rem = typename Repeat<T, N-1>::Seq;
|
||||
using Seq = typename Prepend<T,Rem>::Seq;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Repeat<T,0>
|
||||
{
|
||||
using Seq = TySeq<>;
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct _Adapt
|
||||
{
|
||||
using NFold = typename Repeat<T,N>::Seq;
|
||||
using Array = typename RebindVariadic<ArrayAdapt, NFold>::Type;
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
using _AdaptArray_t = typename _Adapt<T,N>::Array;
|
||||
}
|
||||
|
||||
template<typename T, typename...TT>
|
||||
struct ArrayAdapt<T,TT...>
|
||||
: std::array<T, 1+sizeof...(TT)>
|
||||
{
|
||||
static_assert (AllSame<T,TT...>()
|
||||
,"Array can only hold elements of uniform type");
|
||||
using Array = std::array<T, 1+sizeof...(TT)>;
|
||||
|
||||
ArrayAdapt (Array const& o) : Array{o} { }
|
||||
ArrayAdapt (Array && r) : Array{move(r)} { }
|
||||
|
||||
template<typename...XS>
|
||||
ArrayAdapt (XS&& ...inits)
|
||||
: Array{std::forward<XS> (inits)...}
|
||||
{ }
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct TupleClosureBuilder<std::array<T,N>>
|
||||
: TupleClosureBuilder<_AdaptArray_t<T,N>>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
||||
|
||||
namespace std { // Specialisation to support C++ »Tuple Protocol« and structured bindings.
|
||||
|
||||
/** determine compile-time fixed size of the adapted std::array */
|
||||
template<typename...TTT>
|
||||
struct tuple_size<lib::meta::ArrayAdapt<TTT...> >
|
||||
: integral_constant<size_t, sizeof...(TTT)>
|
||||
{ };
|
||||
|
||||
/** expose the element type of the adapted std::array */
|
||||
template<size_t I, typename...TTT>
|
||||
struct tuple_element<I, lib::meta::ArrayAdapt<TTT...> >
|
||||
: tuple_element<I, typename lib::meta::ArrayAdapt<TTT...>::Array>
|
||||
{ };
|
||||
|
||||
// Note: the std::get<i> function will pick the subclass
|
||||
}
|
||||
#endif /*LIB_META_TUPLE_CLOSURE_H*/
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/meta/tuple-closure.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"////////////////TODO
|
||||
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ namespace test {
|
|||
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
using std::array;
|
||||
using std::make_tuple;
|
||||
using lib::meta::_Fun;
|
||||
using lib::test::showType;
|
||||
|
|
@ -53,6 +55,7 @@ namespace test {
|
|||
{
|
||||
tuple_bindFront();
|
||||
tuple_bindBack();
|
||||
array_bindFront();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -94,6 +97,23 @@ SHOW_EXPR(showType<FunType::Sig>())
|
|||
Tup t2 = c2(make_tuple (-1));
|
||||
CHECK (t2 == "«tuple<int, double, string>»──(-1,3.1415927,pi)"_expect);
|
||||
}
|
||||
|
||||
|
||||
/** @test use a std::array and handle it like a tuple to pre-fix some elements
|
||||
*/
|
||||
void
|
||||
array_bindFront()
|
||||
{
|
||||
using Arr = array<int,5>;
|
||||
using Builder = TupleClosureBuilder<Arr>;
|
||||
|
||||
auto cons = Builder::closeFront (1u,2.3);
|
||||
using FunType = _Fun<decltype(cons)>;
|
||||
CHECK (showType<FunType::Sig>() == "ArrayAdapt<int, int, int, int, int> (ArrayAdapt<int, int, int>)"_expect);
|
||||
|
||||
Arr arr = cons({3,4,5});
|
||||
CHECK (arr == "[1, 2, 3, 4, 5]"_expect);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -91202,11 +91202,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1733946498997" ID="ID_1699016974" MODIFIED="1733946531556" TEXT="läßt sich direkt auf std::integral_constant zurückführen"/>
|
||||
<node CREATED="1733946533117" ID="ID_1111331922" MODIFIED="1733946542098" TEXT="implementiert für beliebige HeteroData"/>
|
||||
<node CREATED="1733946542902" ID="ID_139021842" MODIFIED="1733946550153" TEXT="auch gleich implementiert für StorageFrame"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1733946551317" FOLDED="true" ID="ID_555431810" MODIFIED="1733946586881" TEXT="Beachte: Template-Spezialisierungen greifen nicht für abgeleitete Klassen">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1733946551317" ID="ID_555431810" MODIFIED="1739806634258" TEXT="Beachte: Template-Spezialisierungen greifen nicht für abgeleitete Klassen">
|
||||
<arrowlink COLOR="#833d47" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-889;37;" ID="Arrow_ID_395284049" STARTARROW="None" STARTINCLINATION="-945;38;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1733946590316" ID="ID_626664530" MODIFIED="1733946600694" TEXT="nach zwemal Nachdenken: ist auch sinnvoll"/>
|
||||
<node CREATED="1733946621803" ID="ID_333291639" MODIFIED="1733946638813" TEXT="man würde dann statisch auf der Basis-Klasse operieren"/>
|
||||
<node CREATED="1733946640233" ID="ID_1111919688" MODIFIED="1733946648532" TEXT="es gäbe keine Erweiterungspunkte"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1733946654687" ID="ID_1461671576" MODIFIED="1733946693210" TEXT="tuple_element">
|
||||
|
|
@ -106029,6 +106027,39 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node COLOR="#338800" CREATED="1739752776321" ID="ID_376565948" MODIFIED="1739752785816" TEXT="TupleClosure_test zur Dokumentation">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739756728914" ID="ID_1671606956" MODIFIED="1739813490672" TEXT="Auf std::array anwendbar machen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739756741667" ID="ID_20824263" MODIFIED="1739813448142" TEXT="Problem: spezielle Typsignatur">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1739756760373" ID="ID_753184722" MODIFIED="1739756775186" TEXT="deshalb ist in jedem Fall eine partielle Spezialisierung notwendig"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1739756922215" ID="ID_1294911921" MODIFIED="1739798944791" TEXT="Problem: eine Builder-Funktion mit expliziter Argument-Anzahl">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1739756977184" ID="ID_1621203501" MODIFIED="1739757006679" TEXT="den Signatur-Typ könnte man noch leicht synthetisieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
BuildFunSig
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1739757025236" ID="ID_416963925" MODIFIED="1739757054617" TEXT="aber woher bekomme ich die zu verarbeitende Funktion??"/>
|
||||
<node COLOR="#5b280f" CREATED="1739798954692" ID="ID_381914136" MODIFIED="1739798965636" TEXT="als std::function aufbauen...">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739798967457" ID="ID_1274106457" MODIFIED="1739813473419" TEXT="anderer Ansatz: Tupel-Typsignatur emulieren">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1739798985823" ID="ID_9547449" MODIFIED="1739799013054" TEXT="...dann könnte die Standard-Impl verwendet werden"/>
|
||||
<node CREATED="1739799014639" ID="ID_205042889" MODIFIED="1739799031581" TEXT="brauche dafür einen automatisch konvertierbaren Adapter"/>
|
||||
<node CREATED="1739807307000" ID="ID_382558613" MODIFIED="1739812304265" TEXT="muß dann wohl Tuple-Protocol reimplementieren">
|
||||
<arrowlink COLOR="#846867" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-1112;-50;" ID="Arrow_ID_577510339" STARTARROW="None" STARTINCLINATION="-1320;72;"/>
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -154188,7 +154219,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
Einschränkungen aufrufbar, aber diesen Umstand kann man nur ausnützen, solange das Lambda keine captures hat; denn andernfalls wird es ein wirkliches Objekt mit Storage und Lebenszyklus.
|
||||
</p>
|
||||
<p>
|
||||
<i>Gefährlich wird es</i> aber, wenn man auf den Umkehrschluß aufbaut, mit der Annahme, eine <b>bool-konvertierbare Funktion sei deaktivierbar</b>. Also wenn man dieser Flag eine zusätzliche Bedeutung zuweist
|
||||
<i>Gefährlich wird es </i>aber, wenn man auf den Umkehrschluß aufbaut, mit der Annahme, eine <b>bool-konvertierbare Funktion sei deaktivierbar</b>. Also wenn man dieser Flag eine zusätzliche Bedeutung zuweist
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
|
|
@ -154196,7 +154227,7 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<node COLOR="#435e98" CREATED="1734712435722" ID="ID_1295746147" MODIFIED="1734712695180" TEXT="beide Fälle sind mit Type-Traits unterscheidbar">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1734712469719" ID="ID_1645609663" MODIFIED="1734712480849" TEXT="std::function ist nur explizit bool-Konvertierbar"/>
|
||||
<node CREATED="1734712482172" ID="ID_261058818" MODIFIED="1734712533377" TEXT="die Konvertierbarkeit das triviale λ in den Signatur-Pointer kann man detektierren"/>
|
||||
<node CREATED="1734712482172" ID="ID_261058818" MODIFIED="1734712482172" TEXT="die Konvertierbarkeit eines trivialen λ in den Signatur-Pointer kann man detektieren"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1734724075728" ID="ID_1330421689" LINK="#ID_475098889" MODIFIED="1734724182332" STYLE="bubble" TEXT="...siehe Lösung in _ParamFun (feed-manifold.hpp)">
|
||||
<icon BUILTIN="list"/>
|
||||
|
|
@ -154576,8 +154607,90 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<node CREATED="1703176027969" ID="ID_434248727" MODIFIED="1703176047234" TEXT="Conversions happen at asignment or force-conversion and can alter the value"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1739806612780" ID="ID_1137910648" MODIFIED="1739806618430" TEXT="Spezialisierungen">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1733946551317" ID="ID_872833596" MODIFIED="1739812304266" TEXT="Template-Spezialisierungen greifen nicht für abgeleitete Klassen">
|
||||
<linktarget COLOR="#833d47" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-889;37;" ID="Arrow_ID_395284049" SOURCE="ID_555431810" STARTARROW="None" STARTINCLINATION="-945;38;"/>
|
||||
<linktarget COLOR="#846867" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-1112;-50;" ID="Arrow_ID_577510339" SOURCE="ID_382558613" STARTARROW="None" STARTINCLINATION="-1320;72;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1733946590316" ID="ID_346822453" MODIFIED="1739807049760" TEXT="nach zwemal Nachdenken: ist auch sinnvoll">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Auf den ersten Blick könnte man meinen, hier sollte die »is-a«-Relation wirksam werden. Allerdings kann die C++-Sprache das nicht leisten. Die funktionale Template-Subsprache ist rein statisch und komplett explizit: würde eine Template-Spezialisierung für einen Subtyp aktiviert, dann würde die Implementierung statisch auf der Basis-Klasse operieren, Value-Objekte würden geSLICEd und virtueller Dispatch würde aus dem Objekt heraus nicht stattfinden (weil es den this-Typ der Basisklasse verwenden muß). Wohingegen ein nach außen geleiteter Aufruf über eine Rück-Referenz dann doch wieder eine eventuell vorhandene VTable verwenden würde. Es gäbe somit keine zuverlässig wirksamen Erweiterungspunkte....
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="smiley-neutral"/>
|
||||
</node>
|
||||
<node CREATED="1739807051288" ID="ID_1504352780" MODIFIED="1739807211620" TEXT="relevantes Beispiel: »Tuple-Protocol«">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Angenommen, wir haben eine Klasse, die aus std::tuple ableitet. Man würde sich wünschen, diese würde automatisch am Tuple-Protocol partizipieren. Tut sie aber nicht, weil schon die Spezialisierung von std::tuple_size nicht greift. Das ist aber auch gut so, denn sonst wäre man auf die Implementierung von std::tuple festgelegt, und könnte z.B. keine Anpassungen am Storage-Management machen. Wenn man <i>so etwas möchte, dann sollte man die klassische-OO verwenden.</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1739807542287" ID="ID_1950397403" MODIFIED="1739807563117" TEXT="Vorsicht Falle: Funktion-Overloads beachten die Basisklasse">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1739806725444" ID="ID_117708999" MODIFIED="1739806732689" TEXT="Concepts?">
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1739804758227" ID="ID_1591357203" MODIFIED="1739804766069" TEXT="overload resolution">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1620405462300" ID="ID_1712821553" LINK="https://issues.lumiera.org/ticket/963" MODIFIED="1739804484292" TEXT="Probleme mit Variadic-Template-Konstruktor (#963)">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1739804086379" ID="ID_1261892764" MODIFIED="1739804259340" TEXT="der gilt als ein besserer match ggü generiertem Copy-Konstruktor">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Jede mögliche Template-Instantiierung wird als konkret gegebene Implementierung dem Overload-Resolution-Set hinzugefügt. Eine genau passende konkrete Implementierung wird gegenüber einer nur inferierten / synthetisierten Implementierung vorgezogen, und auch gegenüber einer konkreten Implementierung, für die eine Typ-Konvertierung notwendig ist.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1739804265419" ID="ID_1015040603" MODIFIED="1739804282815" TEXT="man muß dann die Copy-Konstrukturen explizit dazu definieren"/>
|
||||
<node CREATED="1739804283513" ID="ID_1923467578" MODIFIED="1739804366546" TEXT="oder den Template-Konstruktor im Spezialfall deaktivieren">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1739804303374" ID="ID_1920192438" MODIFIED="1739804353277">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<font color="#827474" face="Monospaced">lib::meta::</font><font color="#392f56" face="Monospaced"><b>disable_if_self</b></font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1620405445951" ID="ID_1127258714" MODIFIED="1620405460977" TEXT="»perfect forwarding«">
|
||||
<node CREATED="1620405462300" ID="ID_1712821553" MODIFIED="1620405478341" TEXT="hatte nun mehrfach Probleme in Kombination mit Variadic-Templates"/>
|
||||
<node BACKGROUND_COLOR="#d5bfb3" CREATED="1739804777416" ID="ID_1413281090" MODIFIED="1739804885525" TEXT="Vorsicht Falle: setzt Match auf freien Template-Parameter voraus">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1739804887609" ID="ID_357922580" MODIFIED="1739804899364" TEXT="Type&& ist stets eine RValue-Referenz"/>
|
||||
<node CREATED="1739804907078" ID="ID_413386124" MODIFIED="1739805133069" TEXT="aber template<typename X> X&& ⟹ X kann als Type const& deduziert werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ABER nur wenn der Template-Parameter <b>für diesen konkreten Aufruf</b>  instantiiert wird; ein Typ-Parameter einer umschließenden Klasse gilt bereits als fest gebunden, also <i>funktioniert mit damit kein »perfect forwarding«.</i> Im Besonderen bei Konstruktoren ist das eine häufig anzutreffende Falle
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1739804952757" ID="ID_996711039" MODIFIED="1739804967987" TEXT="es ist und bleibt ein Compilerbau-Trick">
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1620405479689" ID="ID_53418276" MODIFIED="1620405514581" TEXT="std::forward<ARGS>(args) ... ">
|
||||
<node CREATED="1620405515532" ID="ID_89296387" MODIFIED="1620405524655" TEXT="wenn man damit einen ctor aufruft..."/>
|
||||
<node CREATED="1620405525238" ID="ID_728173351" MODIFIED="1620405542709" TEXT="dann wählt das den copy-ctor, nicht den move-ctor"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue