<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[perfekt forwarding richtig verstehen]]></title><description><![CDATA[<p>hallo,<br />
ich habe perfect forwarding noch nicht richtig verstanden:<br />
oder zumindest, wie man funktionen schreibt, die mit typen hantieren, die viel zu kopieren sind.</p>
<p>Dazu habe ich mir ein kleines mwe überlegt, das keinen wirklichen sinn ergibt sondern nur eine wrapper funktion implementiert, mit der anschließend perfect forwarding gemacht werden kann.</p>
<p>vor c++11 wurden doch die funktionen so geschrieben, dass constrefs übergeben wurden, also etwa sowas:</p>
<pre><code>#include &lt;vector&gt;
#include &lt;initializer_list&gt;
#include &lt;iostream&gt;

class cls {
    public:
        cls() = delete;
        cls(int intval, std::initializer_list&lt;int&gt; vec) 
            : _intval(intval), _vec(vec){
                std::cout &lt;&lt; &quot;called Parametrized-Construct&quot; &lt;&lt; std::endl;
            }
        cls(const cls &amp;inst) 
            : _intval(inst._intval), _vec(inst._vec){
                std::cout &lt;&lt; &quot;called Copy-Construct&quot; &lt;&lt; std::endl;
            }
        cls(cls &amp;&amp;inst) 
            : _intval(std::move(inst._intval)), _vec(std::move(inst._vec)){
                std::cout &lt;&lt; &quot;called Move-Construct&quot; &lt;&lt; std::endl;
            }   
        ~cls() {std::cout &lt;&lt; &quot;called Destruct&quot; &lt;&lt; std::endl;}
        int _intval;
        std::vector&lt;int&gt; _vec;
};

template &lt;typename T&gt;
void func_old(const T &amp;arg) {
    std::cout &lt;&lt; &quot;int:&quot; &lt;&lt; arg._intval &lt;&lt; &quot;, vec: &quot;;
    for(int i  : arg._vec) {
        std::cout &lt;&lt; i &lt;&lt; &quot;, &quot;;
    }   
    std::cout &lt;&lt; std::endl;
}

template &lt;typename T&gt;
void wrapper_old(const T &amp;arg) {
    func_old(arg);
}

int main() {
    {
    cls a(1, {1,2,3,4,5});
    cls b(3, {4,5,3,4,5});
    wrapper_old(a);
    wrapper_old(cls(2, {2,3,4,5,6}));
    wrapper_old(cls(a));
    wrapper_old(std::move(a));
    wrapper_old(cls(std::move(b)));
    }
    return 0;
}
</code></pre>
<p>Mit C++11 wurde nun perfect forwarding eingeführt und es sind nun auch universal-references möglich:<br />
Also etwa sowas:</p>
<pre><code>template &lt;typename T&gt;
void func_new(T &amp;&amp;arg) {
    std::cout &lt;&lt; &quot;int:&quot; &lt;&lt; arg._intval &lt;&lt; &quot;, vec: &quot;;
    for(int i  : arg._vec) {
        std::cout &lt;&lt; i &lt;&lt; &quot;, &quot;;
    }
    std::cout &lt;&lt; std::endl;
}

template &lt;typename T&gt;
void wrapper_new(T &amp;&amp;arg) {
    func_new(std::forward&lt;decltype(arg)&gt;(arg));
}

int main() {
    {
    cls a(1, {1,2,3,4,5});
    cls b(3, {4,5,3,4,5});
    wrapper_new(a);
    wrapper_new(cls(2, {2,3,4,5,6}));
    wrapper_new(cls(a));
    wrapper_new(std::move(a));
    wrapper_new(cls(std::move(b)));
    }
    return 0;
}
</code></pre>
<p>Ist diese neue Form nun besser oder schlechter?<br />
Wie sollte man nun funktionen schreiben? mit der alten methode, mit der neuen oder gibt es eine noch bessere alternative?</p>
<p>danke</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/330309/perfekt-forwarding-richtig-verstehen</link><generator>RSS for Node</generator><lastBuildDate>Fri, 03 Jul 2026 11:35:44 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/330309.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 02 Jan 2015 22:42:19 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Fri, 02 Jan 2015 22:42:19 GMT]]></title><description><![CDATA[<p>hallo,<br />
ich habe perfect forwarding noch nicht richtig verstanden:<br />
oder zumindest, wie man funktionen schreibt, die mit typen hantieren, die viel zu kopieren sind.</p>
<p>Dazu habe ich mir ein kleines mwe überlegt, das keinen wirklichen sinn ergibt sondern nur eine wrapper funktion implementiert, mit der anschließend perfect forwarding gemacht werden kann.</p>
<p>vor c++11 wurden doch die funktionen so geschrieben, dass constrefs übergeben wurden, also etwa sowas:</p>
<pre><code>#include &lt;vector&gt;
#include &lt;initializer_list&gt;
#include &lt;iostream&gt;

class cls {
    public:
        cls() = delete;
        cls(int intval, std::initializer_list&lt;int&gt; vec) 
            : _intval(intval), _vec(vec){
                std::cout &lt;&lt; &quot;called Parametrized-Construct&quot; &lt;&lt; std::endl;
            }
        cls(const cls &amp;inst) 
            : _intval(inst._intval), _vec(inst._vec){
                std::cout &lt;&lt; &quot;called Copy-Construct&quot; &lt;&lt; std::endl;
            }
        cls(cls &amp;&amp;inst) 
            : _intval(std::move(inst._intval)), _vec(std::move(inst._vec)){
                std::cout &lt;&lt; &quot;called Move-Construct&quot; &lt;&lt; std::endl;
            }   
        ~cls() {std::cout &lt;&lt; &quot;called Destruct&quot; &lt;&lt; std::endl;}
        int _intval;
        std::vector&lt;int&gt; _vec;
};

template &lt;typename T&gt;
void func_old(const T &amp;arg) {
    std::cout &lt;&lt; &quot;int:&quot; &lt;&lt; arg._intval &lt;&lt; &quot;, vec: &quot;;
    for(int i  : arg._vec) {
        std::cout &lt;&lt; i &lt;&lt; &quot;, &quot;;
    }   
    std::cout &lt;&lt; std::endl;
}

template &lt;typename T&gt;
void wrapper_old(const T &amp;arg) {
    func_old(arg);
}

int main() {
    {
    cls a(1, {1,2,3,4,5});
    cls b(3, {4,5,3,4,5});
    wrapper_old(a);
    wrapper_old(cls(2, {2,3,4,5,6}));
    wrapper_old(cls(a));
    wrapper_old(std::move(a));
    wrapper_old(cls(std::move(b)));
    }
    return 0;
}
</code></pre>
<p>Mit C++11 wurde nun perfect forwarding eingeführt und es sind nun auch universal-references möglich:<br />
Also etwa sowas:</p>
<pre><code>template &lt;typename T&gt;
void func_new(T &amp;&amp;arg) {
    std::cout &lt;&lt; &quot;int:&quot; &lt;&lt; arg._intval &lt;&lt; &quot;, vec: &quot;;
    for(int i  : arg._vec) {
        std::cout &lt;&lt; i &lt;&lt; &quot;, &quot;;
    }
    std::cout &lt;&lt; std::endl;
}

template &lt;typename T&gt;
void wrapper_new(T &amp;&amp;arg) {
    func_new(std::forward&lt;decltype(arg)&gt;(arg));
}

int main() {
    {
    cls a(1, {1,2,3,4,5});
    cls b(3, {4,5,3,4,5});
    wrapper_new(a);
    wrapper_new(cls(2, {2,3,4,5,6}));
    wrapper_new(cls(a));
    wrapper_new(std::move(a));
    wrapper_new(cls(std::move(b)));
    }
    return 0;
}
</code></pre>
<p>Ist diese neue Form nun besser oder schlechter?<br />
Wie sollte man nun funktionen schreiben? mit der alten methode, mit der neuen oder gibt es eine noch bessere alternative?</p>
<p>danke</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2435837</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2435837</guid><dc:creator><![CDATA[warewin]]></dc:creator><pubDate>Fri, 02 Jan 2015 22:42:19 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Mon, 05 Jan 2015 15:46:59 GMT]]></title><description><![CDATA[<p>warewin schrieb:</p>
<blockquote>
<p>Ist diese neue Form nun besser oder schlechter?<br />
Wie sollte man nun funktionen schreiben? mit der alten methode, mit der neuen oder gibt es eine noch bessere alternative?</p>
</blockquote>
<p>Wenn die Referenz des Objekts nicht irgendwohin weitergereicht (&quot;forwarded&quot;) wird, wo du von einem &quot;move&quot; des Objekts (im Gegensatz zum kopieren) profitierst, macht es in meinen Augen ein &quot;perfect forwarding&quot; im Allgemeinen keinen Sinn. Besonders, wenn du wie in deinem Beispiel lediglich Daten ausgibst.</p>
<p><code>std::forward</code> macht beispielsweise dann Sinn, wenn du innerhalb von <code>func_new</code> den Parameter <code>arg</code> in einen Container einfügen würdest:</p>
<pre><code>template &lt;typename T&gt;
void wrapper_new(T &amp;&amp;arg) {
    func_new(std::forward&lt;T&gt;(arg));
}

template &lt;typename T&gt;
void func_new(T &amp;&amp;arg) {
    std::vector&lt;T&gt; v;
    // Muss natürlich std::forward&lt;T&gt;(arg) statt 
    // std::forward(arg) heissen, Dank an Arcoth
    // für den aufmerksamen Code-Review!
    v.push_back(std::forward&lt;T&gt;(arg));
}

...

// Alle in den 4 Funktionsaufrufen übergebenen
// Argumente sind rvalues (temporäre, namenlose
// Objekte oder mit std::move explizit in eine
// rvalue-Referenz gecastet).
wrapper_new(cls(2, {2,3,4,5,6}));
wrapper_new(cls(a));
wrapper_new(std::move(a));
wrapper_new(cls(std::move(b)));
</code></pre>
<p>Hier sorgen die <code>std::forward</code> dafür dass in allen 4 Fällen die &quot;value&quot;-Kategorie des ursprünglichen Arguments (rvalue) erhalten bleibt, und die Methode <code>std::vector&lt;T&gt;::push_back(T&amp;&amp;)</code> aufgerufen wird, die ihrerseits wieder dafür sorgt (wahrscheinlich ebenfalls durch ein <code>std::forward</code> ), dass die eingefügten Objekte mittels des Move-Konstruktors von <code>cls</code> erzeugt werden.</p>
<p>Oder vielleicht etwas simpler:</p>
<pre><code>template &lt;typename T&gt;
void func_new(T arg) {
}

template &lt;typename T&gt;
void wrapper_new(T &amp;&amp;arg) {
    func_new(std::forward&lt;T&gt;(arg));
}

...

wrapper_new(a);
wrapper_new(cls(a));
wrapper_new(std::move(a));
</code></pre>
<p>... solte ausgeben:</p>
<pre><code>called Copy-Construct
called Move-Construct
called Move-Construct
</code></pre>
<p>Wenn am Ende der Kette das &quot;geforwardete&quot; Objekt jedoch nicht &quot;gemoved&quot; wird, erschließt sich mir auf Anhieb kein Grund, weshalb man ein solches &quot;Forwarding&quot; einsetzten sollte (auch wenn es sicher gute, jedoch eher exotische Gründe geben mag).</p>
<p>Um deine Frage also konkret zu beantworten: So wie die Funktionen bei dir definiert sind, sind <code>func_old</code> und <code>wrapper_old</code> völlig ausreichend und perfect forwarding bringt dir keinen Vorteil.</p>
<p>Gruss,<br />
Finnegan</p>
<p>P.S.: Habe das <code>std::forward&lt;decltype(arg)&gt;</code> in <code>wrapper_new()</code> durch ein <code>std::forward&lt;U&gt;</code> ersetzt. Letzteres ist auf jeden Fall nicht falsch, während ich mir bei ersterem unsicher bin, ob es äquivalent ist oder nicht eventuell zu einem <code>std::forward&lt;U&amp;&amp;&gt;</code> oder einem <code>std::forward&lt;U&amp;&gt;</code> expandiert wird, was soweit ich informiert bin nicht korrekt ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436012</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436012</guid><dc:creator><![CDATA[Finnegan]]></dc:creator><pubDate>Mon, 05 Jan 2015 15:46:59 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Sun, 04 Jan 2015 22:58:04 GMT]]></title><description><![CDATA[<p>Ja, du solltest auf jeden Fall forwarden. Schon allein wegen der Möglichkeit dass die Funktion die am Ende einer forwarding-Kette steht, e.g. <code>func_new</code> , künftig in einer Weise modifiziert wird die forwarding benötigt/von forwarding profitiert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436013</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436013</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Sun, 04 Jan 2015 22:58:04 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Sun, 04 Jan 2015 23:11:10 GMT]]></title><description><![CDATA[<blockquote>
<p>P.S.: Habe das <code>std::forward&lt;decltype(arg)&gt;</code> in <code>wrapper_new()</code> durch ein std::forward&lt;U&gt; ersetzt. Letzteres ist auf jeden Fall nicht falsch, während ich mir bei ersterem unsicher bin, ob es äquivalent ist oder nicht eventuell zu einem <code>std::forward&lt;U&amp;&amp;&gt;</code> oder einem <code>std::forward&lt;U&amp;&gt;</code> expandiert wird, was soweit ich informiert bin nicht korrekt ist.</p>
</blockquote>
<p>Es ist äquivalent. Dabei muss vor allem reference collapsing sowohl im Rückgabetyp von <code>forward</code> als auch im Parameter von <code>wrapper_new</code> berücksichtigt werden.</p>
<pre><code>template&lt; class T &gt;
T&amp;&amp; forward( typename std::remove_reference&lt;T&gt;::type&amp; t );

template&lt; class T &gt;
T&amp;&amp; forward( typename std::remove_reference&lt;T&gt;::type&amp;&amp; t );

template &lt;typename U&gt; 
void wrapper_new(U &amp;&amp;arg)
{ 
    forward&lt;decltype(arg)&gt;(arg) 
}
</code></pre>
<p>Wenn <code>U</code> eine Referenz ist, ist <code>decltype(arg) == U</code> (aufgrund von reference collapsing).<br />
Wenn <code>U</code> keine Referenz ist, ist <code>decltype(arg) == U&amp;&amp;</code> . Allerdings gibt es dann durch <code>T&amp;&amp;</code> in <code>forward</code> wiederum reference collapsing, sodass der Rückgabetyp <code>U&amp;&amp;</code> wird, was er auch sein soll (da das Argument ein rvalue war und als solches weitergeleitet werden soll).</p>
<p>Allerdings ist</p>
<pre><code>v.push_back(std::forward(arg));
</code></pre>
<p>Schwachsinn und sollte nicht kompilieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436015</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436015</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Sun, 04 Jan 2015 23:11:10 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Sun, 04 Jan 2015 23:22:14 GMT]]></title><description><![CDATA[<p>Arcoth schrieb:</p>
<blockquote>
<p>Ja, du solltest auf jeden Fall forwarden. Schon allein wegen der Möglichkeit dass die Funktion die am Ende einer forwarding-Kette steht, e.g. <code>func_new</code> , künftig in einer Weise modifiziert wird die forwarding benötigt/von forwarding profitiert.</p>
</blockquote>
<p>Ich glaube es schadet der Lesbar- und Wartbarkeit des Codes ganz ordentlich, wenn man beginnen würde, aus <strong>jeder</strong> Funktion bei der die Argumente irgendwann mal irgendwohin gemoved werden können eine Template-Funktion zu machen, bei der alle betreffenden Parameter-Typen deduzierbar sind.</p>
<p>Bei Funktionen wo es deutlich absehbar ist, dass man profitiert, gebe ich dir recht, bei allen anderen möchte ich jedoch nicht erst das &quot;root of all evil&quot; bemühen müssen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
<p>Was natürlich stimmt ist, dass wenn ich schon ein</p>
<pre><code>template &lt;typename T&gt;
void wrapper_new(T &amp;&amp;arg)
</code></pre>
<p>habe, ein <code>std::forward</code> so ziemlich die einzig sinnvolle Wahl ist: Ein <code>std::move</code> kann ich hier nicht machen, da die Funktion auch lvalues &quot;frisst&quot;, und wenn ich nicht ausnutze, dass <code>arg</code> auch eine rvalue-Referenz sein kann, kann ich mir das <code>&amp;&amp;</code> -Geraffel auch gleich sparen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>Finnegan</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436017</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436017</guid><dc:creator><![CDATA[Finnegan]]></dc:creator><pubDate>Sun, 04 Jan 2015 23:22:14 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Sun, 04 Jan 2015 23:28:08 GMT]]></title><description><![CDATA[<blockquote>
<p>Ich glaube es schadet der Lesbar- und Wartbarkeit des Codes ganz ordentlich, wenn man beginnen würde, aus jeder Funktion bei der die Argumente irgendwann mal irgendwohin gemoved werden können eine Template-Funktion zu machen, bei der alle betreffenden Parameter-Typen deduzierbar sind.</p>
</blockquote>
<p>Wenn ich Argumente an etwas forwarde was diese momentan <strong>kopiert</strong> (nicht lediglich auf die Daten zugreift o.ä.), sollte man schon forwarden. Den Kopien sollten an allen Ecken vermieden werden, darum geht es bei perfect forwarding. (Und um overload resolution.)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436018</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436018</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Sun, 04 Jan 2015 23:28:08 GMT</pubDate></item><item><title><![CDATA[Reply to perfekt forwarding richtig verstehen on Sun, 04 Jan 2015 23:41:50 GMT]]></title><description><![CDATA[<p>Arcoth schrieb:</p>
<blockquote>
<p>Wenn ich Argumente an etwas forwarde was diese momentan <strong>kopiert</strong> (nicht lediglich auf die Daten zugreift o.ä.), sollte man schon forwarden. Den Kopien sollten an allen Ecken vermieden werden, darum geht es bei perfect forwarding. (Und um overload resolution.)</p>
</blockquote>
<p>Nichts anderes habe ich behauptet, allerdings war die Frage ob die <code>wrapper/func</code>  <code>_new</code> oder <code>_old</code> -Funktionen besser/schlechter sind, und für den gegebenen Code sind die <code>_new</code> -Varianten schlechter weil sie dasselbe Resultat mit umständlicherem Code erzielen.</p>
<p>Arcoth schrieb:</p>
<blockquote>
<p>Allerdings ist</p>
<pre><code>v.push_back(std::forward(arg));
</code></pre>
<p>Schwachsinn und sollte nicht kompilieren.</p>
</blockquote>
<p>Danke für den diskteten Hinweis auf den Tippfehler, ich wusste gar nicht, dass du auf die Diplomatenschule gegangen bist <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
<p>Finngean</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2436019</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2436019</guid><dc:creator><![CDATA[Finnegan]]></dc:creator><pubDate>Sun, 04 Jan 2015 23:41:50 GMT</pubDate></item></channel></rss>