Library: workaround for tricky problems with Template-Argument-Deduction

We use a DataSrc<DAT> template to access the actual data to be substituted.
However, when applying the Text-Template, we need to pick the right
specialisation, based on the type of the actual data provided.

Here we face several challenges:

 * Class-Template-Argument-Deduction starts from the *primary* template's constructors.
   Without that, the compiler will only try the copy constructor and will
   never see the constructors of partial specialisations.
   This can be fixed by providing a ''dummy constructor''.
 * The specifics of how to provide a custom CTAD deduction guide
   for a **nested template** are not well documented. I have found
   several bug reports, and seemingly one of these bugs failed my
   my various attempts. Moreover it is ''not clear if such a deduction
   guide can even be given outside of the class definition scope.''
   For the intended usage pattern this would be crucial, since users
   are expected to provide further specialisations of the DataSrc-template
 * Thus I resorted to the ''old school solution,'' which is to use
   a ''free builder function'' as an extension point. Thus users could
   provide further overloads for the `buildDataSrc()` function.
 * Unfortunately, SFINAE-Tricks are way more limited for function overload.
   Thus it seems impossible to have a generic and more specialised cases,
   unless all special cases are disjoint.

Thus the solution is far from perfect, ''yet for the current situation it seems
sufficient'' (and C++20 Concepts will greatly help to resolve this kind of problems)
This commit is contained in:
Fischlurch 2024-03-25 23:41:14 +01:00
parent a89e272e35
commit 4e26d655a8
2 changed files with 191 additions and 12 deletions

View file

@ -317,8 +317,6 @@ namespace lib {
bool loopFurther();
};
template<class DAT>
using InstanceIter = ExploreIter<InstanceCore<DataSource<DAT>>>;
ActionSeq actions_;
@ -328,7 +326,7 @@ namespace lib {
{ }
template<class DAT>
InstanceIter<DAT>
auto
submit (DAT const& data) const;
template<class DAT>
@ -536,6 +534,8 @@ namespace lib {
static_assert (not sizeof(DAT),
"unable to bind this data source "
"for TextTemplate instantiation");
DataSource (DAT const&);
};
using MapS = std::map<string,string>;
@ -561,7 +561,7 @@ namespace lib {
template<>
struct TextTemplate::DataSource<MapS>
{
MapS const * data_;
MapS const * data_{nullptr};
string keyPrefix_{};
bool isNested() { return not isnil (keyPrefix_); }
@ -642,6 +642,29 @@ namespace lib {
}
};
namespace {// help the compiler with picking the proper specialisation for the data binding
template<class STR, typename = meta::enable_if<meta::is_StringLike<STR>> >
inline auto
bindDataSource(STR const& spec)
{
return TextTemplate::DataSource<string>{spec};
}
inline auto
bindDataSource(MapS const& map)
{
return TextTemplate::DataSource<MapS>{map};
}
/* Why this approach? couldn't we use CTAD?
* - for one, there are various compiler bugs related to nested templates and CTAD
* - moreover I am unable to figure out how to write a deduction guide for an
* user provided specialisation, given possibly within another header.
*/
}
/* ======= implementation of the instantiation state ======= */
@ -821,10 +844,10 @@ namespace lib {
* thereby producing a sequence of `std::string_view&`
*/
template<class DAT>
inline TextTemplate::InstanceIter<DAT>
inline auto
TextTemplate::submit (DAT const& data) const
{
return explore (InstanceCore{actions_, DataSource<DAT>{data}});
return explore (InstanceCore{actions_, bindDataSource(data)});
}
/** submit data and materialise rendered results into a single string */

View file

@ -79558,7 +79558,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
<node CREATED="1512923605740" ID="ID_319280946" MODIFIED="1679783009427" TEXT="Fixture">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1679783052390" ID="ID_176106926" MODIFIED="1679783057287" TEXT="gr&#xfc;nden">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1679783052390" ID="ID_176106926" MODIFIED="1711405779536" TEXT="gr&#xfc;nden">
<linktarget COLOR="#fec499" DESTINATION="ID_176106926" ENDARROW="Default" ENDINCLINATION="-584;114;" ID="Arrow_ID_1229368159" SOURCE="ID_51005656" STARTARROW="None" STARTINCLINATION="-150;36;"/>
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1680563536655" ID="ID_1180632123" MODIFIED="1680565151548" TEXT="Fixture: einfacher Clip">
@ -113501,14 +113501,93 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1711385624332" ID="ID_1369205664" MODIFIED="1711385632315" TEXT="Probleme mit der Typ-Inferenz">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#a50125" CREATED="1711385624332" ID="ID_1369205664" MODIFIED="1711416595595" TEXT="Probleme mit der Typ-Inferenz">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711385634139" ID="ID_1398666279" MODIFIED="1711385663177" TEXT="der Datenquellen-Typ DAT ist direkt angegeben">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1711385647409" ID="ID_61608130" MODIFIED="1711385658671" TEXT="er wird daher literal vom Argument-Typ abgegriffen">
<node BACKGROUND_COLOR="#ccb37e" COLOR="#7614dc" CREATED="1711385647409" ID="ID_61608130" MODIFIED="1711416564386" TEXT="er wird daher literal vom Argument-Typ abgegriffen">
<icon BUILTIN="broken-line"/>
<node CREATED="1711406517514" ID="ID_1242921809" MODIFIED="1711406555810">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
zun&#228;chst einmal: Deklaration kann <font face="Monospaced" color="#1524b7">auto</font>&#160;verwenden
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1711406562556" ID="ID_21985660" MODIFIED="1711406577582" TEXT="...sofern dann weiter unten, bei der Definition der Typ inferiert werden kann"/>
<node CREATED="1711406579542" ID="ID_304269568" MODIFIED="1711406597765" TEXT="damit ist schon mal die Festlegung auf dem Retun-Type aufgehoben">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#d5a189" COLOR="#690f14" CREATED="1711406602173" ID="ID_703682169" LINK="#ID_24293979" MODIFIED="1711406687580" TEXT="Class-Template-Argument-Deduction &#x27f9; Falle bei partieller Spezialisierung">
<icon BUILTIN="clanbomber"/>
<node COLOR="#8d2b6b" CREATED="1711406755346" HGAP="31" ID="ID_866002002" MODIFIED="1711406886648" TEXT="Compiler findet nur den Copy-Konstruktor" VSHIFT="4">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Grund: die expliziten Spezialisierungen kommen &#252;berhaupt erst ins's Spiel, wenn der Compiler die konkreten Template-Argumente bereits erschlossen hat. Vorher schaut er nur in das prim&#228;re Template... und wenn das keinen Konstruktor hat, dann kennt der Compiler nur den Copy-Konstruktor. <i>Die resultierende Fehlermeldung ist dann unglaublich hilfreich...</i>
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="smiley-angry"/>
</node>
</node>
<node CREATED="1711406706369" ID="ID_1041764555" MODIFIED="1711406720779" TEXT="weiteres Problem: bekannte Bugs im GCC-8 f&#xfc;r nested Types"/>
<node COLOR="#338800" CREATED="1711406725495" ID="ID_1509991147" MODIFIED="1711416586404" TEXT="bessere L&#xf6;sung: verwende einen extension-Point">
<icon BUILTIN="button_ok"/>
<node CREATED="1711416020912" ID="ID_843629573" MODIFIED="1711416500243" TEXT="grrr... funktioniert auch nur so halbwegs">
<icon BUILTIN="smily_bad"/>
</node>
<node CREATED="1711416035886" ID="ID_1628187918" MODIFIED="1711416056010" TEXT="kann keine generische catch-All-Funktion haben">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#5b280f" CREATED="1711416080681" ID="ID_1704611898" MODIFIED="1711416428174" TEXT="weil diese dann mit einem enable-if-Spezialfall kollidiert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Das sind die Limitierungen bei Function-Overloads. Mit Template-Deduction-Guides h&#228;tten wir dieses Problem vermutlich nicht (wenn wir sie denn schreiben k&#246;nnten).
</p>
<p>
</p>
<p>
<u>Im Detail</u>: Bei der Function Overload-Resolution werden die verschiedenen Kandidaten geordnet. Dabei werden zun&#228;chst <b>alle &#252;bersch&#252;ssigen und Default-Argumente weggestrichen</b>. Konsequenz: ein enable-If kann zwar einen einzelnen Overload <i>entfernen </i>&#8212; wenn er aber <i>nicht entfernt</i>&#160;wurde, stehen zwei &#228;quivalente Overloads da, und es gibt einen Compilation-Fehler. R&#252;ckgabewerte helfen hier auch nichts (die tragen nur zur const-ness-Auswahl bei). Das hei&#223;t, bei Function-Overload-Resolution mu&#223; das enable-If auf einem <b>weiteren</b>&#160; Parameter stehen, der auch <b>tats&#228;chlich verwendet</b>&#160;wird. Und an der Stelle wird's dann wirklich so trickreich, das es mir fragil erscheint.
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="closed"/>
</node>
<node CREATED="1711416429849" ID="ID_1709082514" MODIFIED="1711416453288" TEXT="Kann deshalb nur Spezial-Bindings bieten, kein generisches Binding">
<icon BUILTIN="clanbomber"/>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1711416455813" ID="ID_693243309" MODIFIED="1711416574656" TEXT="f&#xfc;r die aktuelle Aufgabe gen&#xfc;gt das...">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#c2179b" CREATED="1711416468699" ID="ID_1423682198" MODIFIED="1711416581308" TEXT="...und ich habe hier schon viel zu viel Zeit verbracht">
<font ITALIC="true" NAME="SansSerif" SIZE="11"/>
</node>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1711416602634" ID="ID_1124529163" MODIFIED="1711416624154" TEXT="F&#xfc;r nested Scopes: mu&#xdf; RegExp um Quotes erweitern">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1710793367246" ID="ID_1695880616" MODIFIED="1710793369256" TEXT="ETD">
@ -120849,7 +120928,8 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node CREATED="1695776592132" FOLDED="true" ID="ID_1103669600" LINK="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_class_templates" MODIFIED="1695779285785" TEXT="via Class Template Argument Deduction (CTAD)">
<node CREATED="1695776592132" FOLDED="true" ID="ID_1103669600" LINK="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_class_templates" MODIFIED="1711405835692" TEXT="via Class Template Argument Deduction (CTAD)">
<arrowlink COLOR="#65354c" DESTINATION="ID_135618716" ENDARROW="Default" ENDINCLINATION="21;-62;" ID="Arrow_ID_696408734" STARTARROW="None" STARTINCLINATION="-2;93;"/>
<linktarget COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_344305057" SOURCE="ID_505417061" STARTARROW="None" STARTINCLINATION="-2530;150;"/>
<linktarget COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_171962477" SOURCE="ID_313781081" STARTARROW="None" STARTINCLINATION="-729;83;"/>
<node CREATED="1695776635546" ID="ID_536392621" MODIFIED="1695776837788" TEXT="geht normalerweise nicht &#x2014; da keine &#xbb;universelle Referenz&#xab;">
@ -121044,6 +121124,80 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node CREATED="1711405781006" FOLDED="true" ID="ID_135618716" LINK="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_class_templates" MODIFIED="1711406693840" TEXT="Deduction Guides (CTAD)">
<linktarget COLOR="#65354c" DESTINATION="ID_135618716" ENDARROW="Default" ENDINCLINATION="21;-62;" ID="Arrow_ID_696408734" SOURCE="ID_1103669600" STARTARROW="None" STARTINCLINATION="-2;93;"/>
<node CREATED="1711405899493" ID="ID_423341464" MODIFIED="1711406049382" STYLE="bubble">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<table http-equiv="content-type" content="text/html; charset=utf-8" class="t-sdsc-begin">
<tr class="t-sdsc">
<td class="t-sdsc-nopad">
explicit-specifier<font color="#1cab6b" size="1">&#65279;(optional)</font>&#160;template-name&#160;<code><b>(</b></code>&#160; parameter-decl-clause&#160;<code><b>) -&gt;</b></code>&#160;simple-template-id&#160; <code><b>;</b></code>
</td>
<td class="t-sdsc-nopad">
</td>
</tr>
</table>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711406071698" ID="ID_749416456" MODIFIED="1711406477694" TEXT="Fallen / Probleme">
<icon BUILTIN="clanbomber"/>
<node CREATED="1711406084107" ID="ID_200798811" MODIFIED="1711406113133" TEXT="nested types: must be &#x201e;in same semantic scope&#x201c;">
<node CREATED="1711406116584" ID="ID_50413732" MODIFIED="1711406152887" TEXT="unklar ob das auch extern mit enstprechender Qualifikation m&#xf6;glich ist"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1711406153643" ID="ID_490704661" MODIFIED="1711406166059" TEXT="diverse Compiler-Bugs wurden dokumentiert">
<icon BUILTIN="broken-line"/>
</node>
</node>
<node CREATED="1711406206524" ID="ID_1416799059" MODIFIED="1711406241333">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Automatic Deduction setzt ctor im <b>prim&#228;ren</b>&#160; Template vorraus
</p>
</body>
</html></richcontent>
<node CREATED="1711406243535" ID="ID_1708090758" MODIFIED="1711406253229" TEXT="hei&#xdf;t: wenn man ein leeres prim&#xe4;res Template hat"/>
<node CREATED="1711406253820" ID="ID_985724957" MODIFIED="1711406261329" TEXT="+ diverse partielle Spezialisierungen"/>
<node BACKGROUND_COLOR="#d6b67b" COLOR="#a50125" CREATED="1711406265488" ID="ID_24293979" MODIFIED="1711406390599">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
&#10233; dann findet der Compiler ohne Hilfe <b>keinen Construktor</b>
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
bzw. er findet nur den Copy-Konstruktur
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node CREATED="1711406413576" ID="ID_938637088" MODIFIED="1711406457248" TEXT="Workaround">
<icon BUILTIN="idea"/>
<node CREATED="1711406417888" ID="ID_49380332" MODIFIED="1711406430778" TEXT="Extension-Point &#xfc;ber eine Builder-Methode"/>
<node CREATED="1711406433974" ID="ID_1423963010" MODIFIED="1711406445208" TEXT="die macht eigentlich das Gleiche, wie der Deduction-Guide"/>
<node CREATED="1711406445892" ID="ID_1128807069" MODIFIED="1711406454926" TEXT="nur kann zudem auch noch die Weitergabe der Parameter steuern"/>
</node>
</node>
<node CREATED="1622386272743" ID="ID_1645901699" MODIFIED="1622386277362" TEXT="I/O">
<node CREATED="1622386278646" ID="ID_359102162" MODIFIED="1622386285472" TEXT="sehr gro&#xdf;e Dateien">
<node CREATED="1622386212262" ID="ID_1502979331" LINK="https://stackoverflow.com/a/11564931" MODIFIED="1622386241238" TEXT="Stackoverflow: schreiben einer sehr gro&#xdf;en Datei (C++14)"/>
@ -122442,7 +122596,9 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
</node>
<node CREATED="1710633728708" ID="ID_1898552649" MODIFIED="1710633858137" TEXT="Gnuplot: data visualisation">
<linktarget COLOR="#425fc8" DESTINATION="ID_1898552649" ENDARROW="Default" ENDINCLINATION="-1042;110;" ID="Arrow_ID_1130805562" SOURCE="ID_395770848" STARTARROW="None" STARTINCLINATION="-1030;94;"/>
<node CREATED="1710633903677" ID="ID_1723847579" MODIFIED="1710633905974" TEXT="Docu">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1710633903677" ID="ID_1723847579" MODIFIED="1711405628258" TEXT="Doku">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="info"/>
<node CREATED="1710633912724" ID="ID_1018319399" LINK="http://gnuplot.info/docs_5.5/Overview.html" MODIFIED="1710633928705" TEXT="Overview"/>
<node CREATED="1710633971367" ID="ID_260122422" LINK="gnuplotting.org/" MODIFIED="1710633978050" TEXT="Tutorials"/>
<node CREATED="1710633929641" ID="ID_1371157643" LINK="http://www.gnuplot.info/faq/index.html" MODIFIED="1710633941539" TEXT="FAQ"/>
@ -123194,7 +123350,7 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
<arrowlink COLOR="#fec499" DESTINATION="ID_754563967" ENDARROW="Default" ENDINCLINATION="-691;58;" ID="Arrow_ID_1893379752" STARTARROW="None" STARTINCLINATION="-230;29;"/>
<icon BUILTIN="hourglass"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1680561843520" ID="ID_51005656" MODIFIED="1680566910795" TEXT="Fixture">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1680561843520" ID="ID_51005656" MODIFIED="1711405779536" TEXT="Fixture">
<arrowlink COLOR="#fec499" DESTINATION="ID_176106926" ENDARROW="Default" ENDINCLINATION="-584;114;" ID="Arrow_ID_1229368159" STARTARROW="None" STARTINCLINATION="-150;36;"/>
<icon BUILTIN="hourglass"/>
</node>