From 4a7e1eeb3654e01457a3f2703d0ea9b001fe1850 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 12 Dec 2024 04:38:55 +0100 Subject: [PATCH] Invocation: problems with function template overload resolution Why is our specialisation of `std::get` not picked up by the compiler? * it must somehow be related to the fact that `std::tuple` itself is a base class of lib::HeteroData * if we remove this inheritance relation, our specialisation is used by the compiler and works as intended * however, this strange behaviour can not be reproduced in a simple synthetic setup It must be some further subtlety which marks the tuple case as preferrable --- research/try.cpp | 144 +++++++++-------------------- src/lib/hetero-data.hpp | 18 ++-- tests/library/hetero-data-test.cpp | 4 +- wiki/thinkPad.ichthyo.mm | 123 +++++++++++++++--------- 4 files changed, 136 insertions(+), 153 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 4a3fd4c06..e65095406 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -1,18 +1,15 @@ /* try.cpp - to try out and experiment with new features.... * scons will create the binary bin/try */ +// 12/24 - investigate overload resolution on a templated function similar to std::get // 11/24 - how to define a bare object location comparison predicate // 11/23 - prototype for grouping from iterator /** @file try.cpp - * Attempt to generalise the util::isSameObject, to support a mix of pointers and references. - * This is a long standing requirement, yet I made several failed attempts in the past, - * due to difficulties detecting a pointer after perfect-forwarding the argument. However, - * it is not even necessary to perfect-forward, if all we want is to extract the raw address. - * - * To my defence, I should add that I never took the time to conduct a proper experiment - * in a stand-alone setup; investigating directly in "lib/util.hpp" is a waste of time. + * Find out about the conditions when an overload of a function template is picked. + * This is an investigation regarding the proper way to overload std::get + * especially when the base class of the custom type itself is a tuple. */ typedef unsigned int uint; @@ -25,109 +22,56 @@ typedef unsigned int uint; #include #include +#include -using lib::rani; -using std::move; -using std::string; +using lib::test::showType; - template - inline const void* - getAd (X& x) - { - return static_cast (std::addressof(x)); - } - template - inline const void* - getAd (X* x) - { - return static_cast (x); - } +template +string +showTypes() +{ + return "<" + ((showType()+",") + ... + ">"); +} - template - inline bool - isSameOb (A const& a, B const& b) - { - return getAd(a) - == getAd(b); - } - +using std::tuple; - struct Boo - { - string moo; - short goo; - - Boo(short uh) - : moo{util::toString(uh-1)} - , goo(uh+1) - { } - - operator string() const - { - return moo+util::toString(goo); - } - }; - - struct SuBoo : Boo - { - long poo = rani(goo); - - using Boo::Boo; - }; +struct B { }; - - - inline Boo* - asBoo (void* mem) - {// type tag to mark memory address as Buffer - return static_cast (mem); - } - +struct D1 : B { }; + +struct D2 : D1 { }; + +string getty (B&) { return "getty-B&"; } +string getty (D1&&){ return "getty-D1&&"; } +string getty (D1&) { return "getty-D1&"; } + + + +template +string getty (tuple&) { return "getty-tuple& "+showTypes(); } + + +template +struct F : tuple { }; + +template +struct FD1 : F {}; + +template +struct FD2 : FD1 {}; + + +template +string getty (FD1&) { return "getty-FD1& "+showTypes(); } int main (int, char**) { - Boo boo(23); - Boo booo(23); - Boo* boop = &boo; - Boo const* const beep = boop; - cout << boo << endl; -SHOW_EXPR(util::showAdr(getAd(boo ))) -SHOW_EXPR(util::showAdr(getAd(&boo))) -SHOW_EXPR(util::showAdr(getAd(boop))) -SHOW_EXPR(util::showAdr(getAd(beep))) -SHOW_EXPR(isSameOb(boop, beep)) -SHOW_EXPR(isSameOb(&boop, &beep)) -SHOW_EXPR(isSameOb(boo, beep)) -SHOW_EXPR(isSameOb(*beep, booo)) -SHOW_EXPR(isSameOb(boo, boo.moo)) -SHOW_EXPR(isSameOb(boo, &boo.moo)) -SHOW_EXPR(isSameOb(boo.moo, booo)) -SHOW_EXPR(isSameOb(booo, asBoo(&booo.moo))) -SHOW_EXPR(isSameOb(booo, asBoo(&booo.goo))) - - const void* voo = boop; -SHOW_EXPR(isSameOb(voo, boo)) -SHOW_EXPR(isSameOb(voo, boop)) -SHOW_EXPR(isSameOb(voo, asBoo(&boo.moo))) -SHOW_EXPR(isSameOb(voo, asBoo(&booo.moo))) -SHOW_EXPR(isSameOb(voo, asBoo(&boo.goo))) + D2 d2; + SHOW_EXPR(getty(d2)); - Boo&& roo = move(boo); -SHOW_EXPR(isSameOb(roo, boo)) -SHOW_EXPR(isSameOb(voo, roo)) -SHOW_EXPR(isSameOb(voo, Boo{roo})) - - SuBoo* suBoo = static_cast(&boo); -SHOW_EXPR(isSameOb(boo, suBoo)) -SHOW_EXPR(isSameOb(boo, suBoo->moo)) -SHOW_EXPR(isSameOb(voo, suBoo->moo)) -SHOW_EXPR(isSameOb(voo, suBoo->poo)) - - SuBoo sudo{*suBoo}; -SHOW_EXPR(isSameOb(sudo, suBoo)) - suBoo = &sudo; -SHOW_EXPR(isSameOb(sudo.poo, suBoo->poo)) + FD2 fd2; + SHOW_EXPR(getty(fd2)); cout << "\n.gulp.\n"; return 0; diff --git a/src/lib/hetero-data.hpp b/src/lib/hetero-data.hpp index d6e84c502..f14f08296 100644 --- a/src/lib/hetero-data.hpp +++ b/src/lib/hetero-data.hpp @@ -74,7 +74,7 @@ namespace lib { template struct StorageFrame - : protected StorageLoc + : StorageLoc , std::tuple { using Tuple = std::tuple; @@ -88,13 +88,16 @@ namespace lib { template class HeteroData,TAIL>> - : StorageFrame +// : StorageFrame +// : util::NonCopyable { using _Self = HeteroData; using _Tail = HeteroData; using Tuple = std::tuple; using Frame = StorageFrame; + Frame frame_; + static constexpr size_t localSiz = sizeof...(DATA); template @@ -107,14 +110,17 @@ namespace lib { _Tail& accessTail() { - REQUIRE (Frame::next, "HeteroData storage logic broken: follow-up extent not yet allocated"); - return * reinterpret_cast<_Tail*> (Frame::next); + REQUIRE (frame_.next, "HeteroData storage logic broken: follow-up extent not yet allocated"); + return * reinterpret_cast<_Tail*> (frame_.next); } template friend class HeteroData; ///< allow chained types to use recursive type definitions - using Frame::Frame; + template + HeteroData (INIT&& ...initArgs) + : frame_{std::forward (initArgs)...} + { } public: HeteroData() = default; @@ -135,7 +141,7 @@ namespace lib { { static_assert (slot < size(), "HeteroData access index beyond defined data"); if constexpr (slot < localSiz) - return std::get (*this); + return std::get (frame_); else return accessTail().template get(); } diff --git a/tests/library/hetero-data-test.cpp b/tests/library/hetero-data-test.cpp index 7f25b32e5..b01ab47a5 100644 --- a/tests/library/hetero-data-test.cpp +++ b/tests/library/hetero-data-test.cpp @@ -131,8 +131,8 @@ namespace test{ CHECK ((showType>() == "string"_expect)); CHECK (std::get<0> (chain2) == 42); -// CHECK (std::get<1> (chain2) == "1.618034"_expect); ////////////////////////////TODO somehow the overload for std::tuple takes precedence here -// CHECK (std::get<2> (chain2) == "Φ"_expect); + CHECK (std::get<1> (chain2) == "1.618034"_expect); ////////////////////////////TODO somehow the overload for std::tuple takes precedence here + CHECK (std::get<2> (chain2) == "Φ"_expect); CHECK (std::get<0> (b2) == "1.618034"_expect); CHECK (std::get<1> (b2) == "Φ"_expect); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index cd0699a59..0e9eab455 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -22649,9 +22649,7 @@ - - - +

...da wir unterstellen, daß das Gegenstück im Session-Modell, @@ -22986,9 +22984,7 @@ - - - +

...welche darin besteht, @@ -23396,9 +23392,7 @@ - - - +

Dienst: aktueller Skalenfaktor + Offset @@ -24200,9 +24194,7 @@ - - - +

Auslösen durch signalStructureChange @@ -25342,9 +25334,7 @@ - - - +

nachweislich... @@ -27410,9 +27400,7 @@ - - - +

↶ freeCAD : rechtsdrehend(mathematisch) @@ -30944,9 +30932,7 @@ - - - +

das ist ein reiner (pesistent) presentation state @@ -31769,9 +31755,7 @@ - - - +

window:backdrop:dir-ltr.background box:backdrop:dir-ltr.vertical box:backdrop:dir-ltr[2/3].horizontal widget:backdrop:dir-ltr[2/2] widget:backdrop:dir-ltr paned:backdrop:dir-ltr.vertical widget:backdrop:dir-ltr box:backdrop:dir-ltr.vertical notebook:backdrop:dir-ltr[1/1].frame paned:backdrop:dir-ltr.horizontal box:backdrop:dir-ltr.vertical fork.timeline @@ -35471,9 +35455,7 @@ - - - +

das mag überraschend sein — erst dachte ich, es sein ein Nachteil, aber tatsächlich fügt es sich natürlich in die Layout-Steuerung von GTK ein; denn GTK fragt ja das Widget nach seiner benötigten Ausdehnung, und das ist auch genau der Mechanismus, über den wir eine Beschränkung auf eine vorgegebene zeitliche Ausdehnung realisieren. Zudem hat das Widget die Information über seine eigene Ausdehnung als Zeitangabe vorliegen, und das paßt dann auch gut in dieses Aufrufschema @@ -37735,9 +37717,7 @@ - - - +

Das Ideal wäre, daß man das nicht speziell für Maus, Tastatur, Stift und Hardware einrichten muß, sondern lediglich qualifizieren @@ -38967,9 +38947,7 @@ - - - +

wenn wir trotzdem einen Overrun-Check haben wollen, @@ -39378,9 +39356,7 @@ - - - +

2.Schritt: rektifizieren @@ -39647,9 +39623,7 @@ - - - +

...später möchte ich diesen als eigenen zusätzlichen Freiheitsgrad einführen; dazu muß aber bereits mehr über den Verwendungszusammenhang bekannt sein; insofern habe ich vorerst eine generische Regel implementiert, die den Zoom-Anchor anhand der Position zum Gesamt-Canvas festlegt (ganz am Anfgang liegt er ganz links, am Ende ganz rechts) @@ -40050,9 +40024,7 @@ - - - +

das heißt... @@ -88268,8 +88240,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
sollte im Prinzip ja einfach sein...

- -
+ +
@@ -88296,6 +88268,57 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + + +

+ HeteroData darf dann gar keine Basisklasse haben. Denn die empty-baseclass-optimisation ist optional; letztlich läßt der Standard dem konkreten Compiler einigen Spielraum bezüglich des Speicher-Layouts +

+ +
+
+ + + + + +

+ Die Definition mit dem Frame als Basisklasse erscheint mir sauberer, denn sie legt zweifelsfrei fest, wo der Frame sein soll und daß er mit dem Anfang von HeteroData zusammenfallen soll. Außerdem dokumentiert das eine is-a Beziehung (wenngleich auch die Sichtbarkeit eingeschränkt ist). +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + @@ -142743,7 +142766,17 @@ std::cout << tmpl.render({"what", "World"}) << s - + + + + + + + + + + +