Die Idee ist nicht schlecht, aber dein RAM wird sthönen und der Aufruf einer Webseite sehr lange dauern, weil du be jedem Aufruf erst den String im RAM konstruierst und zurück gibst.
Ich grübel gerade ob man den statischen Teil nicht irgendwie sinnvoll außerhalb der Methoden als Const hinterlegen kann und dann einfach nur beim schreiben in den Socket bestimmte Marker abwartet um dann eben Inhalte einzufüllen (wie in dem ESP spezifischen AsyncWebServer Beispiel oben)
So etwas in der Art wie "<?varName1?>"
Variablen übergibst du am besten mit Hilfe eines Dictionary, also eine Liste von <Key, Value> Paaren
Code:
typedef VarList_t std::Map<std::String, std::String>;
boolean sendHTML(std::String Template, VarList_t aVarList);
VarList_t VarList;
...
VarList.clear();
VarList["varName1"] = "etwas schönes"
if(!sendHTML(irgendeineHTMLmitVarName1darin,VarList) printError();
Wenn jetzt in SendHTML während des senden in dem HTML String ein "<?" gefunden wird, sendet er nciht weiter sondern scannt bis zum passenden "?>" durch. Dann ruft er den Inhalt der Variable aus dem Dictionary und sendet den Inhalt. Danach setzt er nach dem schließenden "?>" den HTML String weiter fort, bis er wieder auf "<?" stößt oder am Ende ankommt.