{"id":3642,"date":"2018-08-05T19:04:15","date_gmt":"2018-08-05T18:04:15","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=3642"},"modified":"2018-08-06T22:25:37","modified_gmt":"2018-08-06T21:25:37","slug":"c-guns-semantics-is-important","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=3642","title":{"rendered":"C++ Guns: semantics is important"},"content":{"rendered":"<p>Einfach N Zufallszahlen ziehen ist einfach. Eigentlich gibt es dar\u00fcber nicht viel zu sagen, aber es ist ein sch\u00f6nes Beispiel f\u00fcr Semantik. (Dank an Ben f\u00fcr die Inspiration).<\/p>\n<p>Wir m\u00fcssen immer den Spagat zwischen Lesbarkeit und Performance machen. Manchmal sind die Verantwortlichkeiten der Funktionen nicht klar zu definieren. Soll die Funktion, welche N Zufallszahlen zieht, auch die Container erstellen in denen sie gespeichert werden? Das w\u00e4re f\u00fcr die Lesbarkeit f\u00f6rderlich, aber f\u00fcr die Performance schlecht. Da bei jedem Aufruf ein neuer Container initialisiert werden muss. Und wenn die Funktion einen bereits initialisierten Container \u00fcbergeben bekommt und auch auf diesen Weg die Daten zur\u00fcck gegeben werden, w\u00e4re der Lesefluss gest\u00f6rt. Vor allem muss beim ersten Aufruf von Hand ein neuer Container initialisiert werden.<\/p>\n<p>F\u00fcr beide Varianten gilt: Keine von Hand geschriebenen Schleifen. Sie enthalten einfach unn\u00f6tige potentielle Fehler. Ein einfacher std::for_each Aufruf ist besser.<br \/>\nHier mein Versuch beide Welten abzudecken. Durch die fehlenden Concepts in C++17 bl\u00e4ht sich der Template Code etwas auf. Aber dieses Problem l\u00f6st sich ja von alleine.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ 7 loc to just call for_each... semantics is important\r\ntemplate&lt;typename Container, typename PRNG, typename Distribution&gt;\r\nauto drawSamples(Container&amp; data, PRNG&amp; r, Distribution&amp; U) {\r\n    static_assert(std::is_arithmetic_v&lt;typename Container::value_type&gt;);\r\n    static_assert(std::is_invocable_v&lt;PRNG&gt;, &quot;PRNG is not invocable&quot;);\r\n    static_assert(std::is_invocable_v&lt;Distribution, PRNG&amp;&gt;, &quot;Distribution is not invocable with PRNG&quot;);\r\n    static_assert(std::is_same_v&lt;typename Container::value_type, typename Distribution::result_type &gt;, &quot;Return type of the distribution and value type of container are not the same&quot;);\r\n\r\n    std::for_each(std::begin(data), std::end(data), &#x5B;&amp;](auto&amp; x){x = U(r);} );\r\n    return data; \/\/ good idea? yes. consistent with the other drawSamples overload\r\n                 \/\/ NO! bad feeling. pass by reference and return by value - it must be a copy somewhere. even with return optimazion.\r\n}\r\n\r\ntemplate&lt;typename PRNG, typename Distribution&gt;\r\nauto drawSamples(int N, PRNG&amp; r, Distribution&amp; U) {\r\n    static_assert(std::is_invocable_v&lt;PRNG&gt;, &quot;PRNG is not invocable&quot;);\r\n    static_assert(std::is_invocable_v&lt;Distribution, PRNG&amp;&gt;, &quot;Distribution is not invocable with PRNG&quot;);    \r\n\r\n    std::vector&lt;typename Distribution::result_type&gt; data(N);\r\n    drawSamples(data, r, U);\r\n    return data;\r\n}\r\n\r\n\r\nauto func() {\r\n    std::minstd_rand r;\r\n    std::uniform_int_distribution&lt;int&gt; U(1, 6);\r\n    std::vector data = drawSamples(10, r, U);\r\n    data = drawSamples(data, r, U);\r\n    return data;\r\n}\r\n<\/pre>\n<p>Bin gespannt ob sich dies in der Praxis bew\u00e4hrt.<\/p>\n<p>update:<br \/>\nIch glaube pass by reference und return by value ist immer eine Kopie. Und damit ineffizient. Selbst mit return Optimierung. Bin mir aber nicht sicher.<br \/>\nVielleicht sieht das ganze mit Iteratoren und Ranges besser aus.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Einfach N Zufallszahlen ziehen ist einfach. Eigentlich gibt es dar\u00fcber nicht viel zu sagen, aber es ist ein sch\u00f6nes Beispiel f\u00fcr Semantik. (Dank an Ben f\u00fcr die Inspiration). Wir m\u00fcssen immer den Spagat zwischen Lesbarkeit und Performance machen. Manchmal sind die Verantwortlichkeiten der Funktionen nicht klar zu definieren. Soll die Funktion, welche N Zufallszahlen zieht, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-3642","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3642","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3642"}],"version-history":[{"count":4,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3642\/revisions"}],"predecessor-version":[{"id":3650,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/3642\/revisions\/3650"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3642"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}