<?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[Threads, Member Function Pointer und Type Erasure]]></title><description><![CDATA[<p>Ich moechte Memberfunktionen innerhalb eines Threads ausfuehren. Dafuer gibt es <code>std::thread</code> . Jedoch soll beim Aufruf des Destruktors automatisch eine Funktion <code>stop</code> aufgerufen werden und mittels <code>join</code> auf das Ende des Threads gewartet werden. Dazu habe ich mir folgendes einfaches Template geschrieben:</p>
<pre><code class="language-cpp">template&lt;typename T, void (T::*Run)(), void (T::*Stop)()&gt;
struct service
{
    service(T&amp; runnable) : runnable(runnable), th(Run, std::ref(runnable)){}

    ~service(){
        (runnable.*Stop)();
        if (th.joinable()) th.join();
    }
private:
    T&amp; runnable;
    std::thread th;
};
</code></pre>
<p>Es kann wie folgt aufgerufen werden:</p>
<pre><code class="language-cpp">struct A {
    void run() { .. }
    void stop() { .. }
};

struct B {
    void exec() { .. }
    void halt() { .. }
};

A a;
B b;

service&lt;A, &amp;A::run, &amp;A::stop&gt; service_a(a);
service&lt;B, &amp;B::exec, &amp;B::halt&gt; service_b(b);
</code></pre>
<p>Jetzt moechte ich nicht staendig ein neuen Typ mittels service-Template erstellen, sondern aehnlich wie bei <code>std::thread</code> einfach Funktion und Objekt uebergeben. Beispiel:</p>
<pre><code class="language-cpp">service2 service_a(&amp;A::stop, &amp;A::run, a)
</code></pre>
<p>Als Loesung bietet sich Type Erasure an. Als Vorlage diente <a href="http://www.cplusplus.com/forum/articles/18756/" rel="nofollow">http://www.cplusplus.com/forum/articles/18756/</a> :</p>
<pre><code class="language-cpp">class service2
{
    struct service_concept
    {
        virtual ~service_concept() {}
    };

    template&lt;typename T, void (T::*Run)(), void (T::*Stop)()&gt;
    struct service_model : service_concept
    {
        service_model(T&amp; runnable) : runnable(runnable), th(Run, std::ref(runnable)){}

        virtual ~service_model(){
            (runnable.*Stop)();
            if (th.joinable()) th.join();
        }

    private:
        T&amp; runnable;
        std::thread th;
    };

    std::shared_ptr&lt;service_concept&gt; obj;

public:
    template&lt;typename T, void (T::*Run)(), void (T::*Stop)() &gt;
    service2(Stop s, Run, T&amp; runnable)
    : obj( new service_model&lt;T, Run, Stop&gt;(runnable) ){}
};
</code></pre>
<p>Leider bekomme ich als Fehler in Zeile 27 <code>error C2061: syntax error : identifier 'Stop'</code> . Frage: Wie biege ich es so hin, dass es uebersetzt wird?</p>
<p>Leider kann ich gerade nicht nachschauen, wie <code>std::function</code> , <code>std::bind</code> bzw. <code>std::thread</code> das machen. Unter Visual Studio 11 Beta verwirren mich die Makros fuer Varadic Templates. Alternativ ueberlege ich gerade, wie eine Loesung mittels <code>std::function</code> ausschaut. Grossartig darueber nachgedacht habe ich jetzt noch nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/304488/threads-member-function-pointer-und-type-erasure</link><generator>RSS for Node</generator><lastBuildDate>Sun, 09 Aug 2026 17:38:02 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/304488.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 07 Jun 2012 13:37:15 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Thu, 07 Jun 2012 15:10:16 GMT]]></title><description><![CDATA[<p>Ich moechte Memberfunktionen innerhalb eines Threads ausfuehren. Dafuer gibt es <code>std::thread</code> . Jedoch soll beim Aufruf des Destruktors automatisch eine Funktion <code>stop</code> aufgerufen werden und mittels <code>join</code> auf das Ende des Threads gewartet werden. Dazu habe ich mir folgendes einfaches Template geschrieben:</p>
<pre><code class="language-cpp">template&lt;typename T, void (T::*Run)(), void (T::*Stop)()&gt;
struct service
{
    service(T&amp; runnable) : runnable(runnable), th(Run, std::ref(runnable)){}

    ~service(){
        (runnable.*Stop)();
        if (th.joinable()) th.join();
    }
private:
    T&amp; runnable;
    std::thread th;
};
</code></pre>
<p>Es kann wie folgt aufgerufen werden:</p>
<pre><code class="language-cpp">struct A {
    void run() { .. }
    void stop() { .. }
};

struct B {
    void exec() { .. }
    void halt() { .. }
};

A a;
B b;

service&lt;A, &amp;A::run, &amp;A::stop&gt; service_a(a);
service&lt;B, &amp;B::exec, &amp;B::halt&gt; service_b(b);
</code></pre>
<p>Jetzt moechte ich nicht staendig ein neuen Typ mittels service-Template erstellen, sondern aehnlich wie bei <code>std::thread</code> einfach Funktion und Objekt uebergeben. Beispiel:</p>
<pre><code class="language-cpp">service2 service_a(&amp;A::stop, &amp;A::run, a)
</code></pre>
<p>Als Loesung bietet sich Type Erasure an. Als Vorlage diente <a href="http://www.cplusplus.com/forum/articles/18756/" rel="nofollow">http://www.cplusplus.com/forum/articles/18756/</a> :</p>
<pre><code class="language-cpp">class service2
{
    struct service_concept
    {
        virtual ~service_concept() {}
    };

    template&lt;typename T, void (T::*Run)(), void (T::*Stop)()&gt;
    struct service_model : service_concept
    {
        service_model(T&amp; runnable) : runnable(runnable), th(Run, std::ref(runnable)){}

        virtual ~service_model(){
            (runnable.*Stop)();
            if (th.joinable()) th.join();
        }

    private:
        T&amp; runnable;
        std::thread th;
    };

    std::shared_ptr&lt;service_concept&gt; obj;

public:
    template&lt;typename T, void (T::*Run)(), void (T::*Stop)() &gt;
    service2(Stop s, Run, T&amp; runnable)
    : obj( new service_model&lt;T, Run, Stop&gt;(runnable) ){}
};
</code></pre>
<p>Leider bekomme ich als Fehler in Zeile 27 <code>error C2061: syntax error : identifier 'Stop'</code> . Frage: Wie biege ich es so hin, dass es uebersetzt wird?</p>
<p>Leider kann ich gerade nicht nachschauen, wie <code>std::function</code> , <code>std::bind</code> bzw. <code>std::thread</code> das machen. Unter Visual Studio 11 Beta verwirren mich die Makros fuer Varadic Templates. Alternativ ueberlege ich gerade, wie eine Loesung mittels <code>std::function</code> ausschaut. Grossartig darueber nachgedacht habe ich jetzt noch nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220602</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220602</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Thu, 07 Jun 2012 15:10:16 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Thu, 07 Jun 2012 17:06:55 GMT]]></title><description><![CDATA[<pre><code class="language-cpp">struct service
{
	typedef std::function&lt;void ()&gt; action;

	template &lt;class F&gt;
    service(F &amp;&amp;run, action stop) : stop(std::move(stop)), th(std::forward&lt;F&gt;(run)){}

    ~service(){
		stop();
        if (th.joinable()) th.join();
    }
private:
	action stop;
    std::thread th;
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2220660</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220660</guid><dc:creator><![CDATA[TyRoXx]]></dc:creator><pubDate>Thu, 07 Jun 2012 17:06:55 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Thu, 07 Jun 2012 22:58:44 GMT]]></title><description><![CDATA[<p>Wenn du die Memberfunktionszeiger als Funktionsargumente (und nicht Templateargumente) übergibst, sind sie im Konstruktor keine konstanten Ausdrücke mehr und können deshalb nicht als Templateargumente von <code>service_model</code> verwendet werden.</p>
<p>Du kannst entweder durchgehend nur noch <code>T</code> als Templateparameter haben und die Memberfunktionszeiger als Variablen speichern, oder du schreibst dir ein Funktionstemplate, das die Memberfunktionszeiger als Templateargumente nimmt:</p>
<pre><code class="language-cpp">auto my_service = create_service&lt;&amp;A::run, &amp;A::stop&gt;(a);
</code></pre>
<p>Mit <code>std::function</code> bist du grundsätzlich viel flexibler, da du nicht auf Memberfunktionszeiger beschränkt bist. Allerdings kann die Laufzeit aufgrund der dynamisch gespeicherten Funktionen minimal schlechter werden, was man aber durch direktes Hardwiren durch Templates beheben kann (d.h. der Typ der Funktionen wäre dann <code>F</code> statt <code>std::function&lt;void()&gt;</code> ). Zudem ist die Aufrufsyntax ein wenig komplizierter, da du wahrscheinlich <code>bind()</code> oder <code>mem_fn()</code> benutzen wirst.</p>
<p>Ausserdem: Verwende <code>std::unique_ptr</code> statt <code>std::shared_ptr</code> , du hast schliesslich keinen geteilten Besitz.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220835</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220835</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Thu, 07 Jun 2012 22:58:44 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Thu, 07 Jun 2012 23:06:02 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>Mit <code>std::function</code> bist du grundsätzlich viel flexibler, da du nicht auf Memberfunktionszeiger beschränkt bist. Allerdings kann die Laufzeit aufgrund der dynamisch gespeicherten Funktionen minimal schlechter werden</p>
</blockquote>
<p>Warum holst du die Performance-Keule heraus? Das ist total unnötig und spielt hier überhaupt keine Rolle, weil das Hantieren mit Threads schon um Größenordnungen teurer ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220841</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220841</guid><dc:creator><![CDATA[TyRoXx]]></dc:creator><pubDate>Thu, 07 Jun 2012 23:06:02 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Fri, 08 Jun 2012 08:01:46 GMT]]></title><description><![CDATA[<p>TyRoXx schrieb:</p>
<blockquote>
<p>Warum holst du die Performance-Keule heraus? Das ist total unnötig</p>
</blockquote>
<p>Warum &quot;Keule&quot;? Ich habe das nur als Randnotiz hinzugefügt, damit knivil, der den <code>std::function</code> -Ansatz nicht kennt, etwas mehr darüber erfährt. Keine Ahnung, was du für ein Problem damit hast, zumal ich extra &quot;minimal&quot; geschrieben habe.</p>
<p>TyRoXx schrieb:</p>
<blockquote>
<p>und spielt hier überhaupt keine Rolle, weil das Hantieren mit Threads schon um Größenordnungen teurer ist.</p>
</blockquote>
<p>Schon mal dran gedacht, dass man in ähnliche Situationen kommen könnte, wo es eine Rolle spielt? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f644.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_rolling_eyes"
      title=":rolling_eyes:"
      alt="🙄"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220915</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220915</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Fri, 08 Jun 2012 08:01:46 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Fri, 08 Jun 2012 08:41:55 GMT]]></title><description><![CDATA[<blockquote>
<p>Wenn du die Memberfunktionszeiger als Funktionsargumente (und nicht Templateargumente) übergibst, sind sie im Konstruktor keine konstanten Ausdrücke mehr und können deshalb nicht als Templateargumente von service_model verwendet werden.</p>
</blockquote>
<p>Ja, dass habe ich auch gemerkt. Ziel ist es, auf Template-Parameter a la create_service&lt;&amp;A::run, &amp;A::stop&gt;(a) zu verzichten. Meine bisheriege Loesung schaut wie folgt aus:</p>
<pre><code class="language-cpp">class service2
{
    struct service_concept
    {
        virtual ~service_concept() {}
    };

    template&lt;typename T&gt;
    struct service_model : service_concept
    {
        service_model(T&amp; runnable, void (T::*stop)(), void (T::*run)() )
        : runnable(runnable), th(run, std::ref(runnable)), stop(stop), run(run)
        {
            std::cout &lt;&lt; &quot;constructor called &quot; &lt;&lt; typeid(*this).name() &lt;&lt; std::endl;
        }

        virtual ~service_model(){
            std::cout &lt;&lt; &quot;destructor called &quot; &lt;&lt; typeid(*this).name() &lt;&lt; std::endl;
            (runnable.*stop)();
            if (th.joinable()) th.join();
        }

    private:
        T&amp; runnable;
        std::thread th;
        void (T::*stop)();
        void (T::*run)();
    };

    std::unique_ptr&lt;service_concept&gt; obj;

public:
    template&lt;typename T&gt;
    service2(void (T::*stop)(),void (T::*run)(), T&amp; runnable)
    : obj( new service_model&lt;T&gt;(std::forward&lt;T&gt;(runnable), stop, run) )
    {
    }
};
</code></pre>
<p>Leider wird unter Visual Studio 11 Beta gleich nach dem Konstruktor der Destruktor aufgerufen. Und ich weiss nicht warum. Vielleicht kann mir jemand helfen. Der Debugger hat mir nicht geholfen. Ein Minimalbeispiel:</p>
<pre><code class="language-cpp">struct type_a {
    type_a() {
        std::cout &lt;&lt; &quot;constructor type_A&quot; &lt;&lt; '\n';
        halt = false;
    }

    void run() {
        while(!halt){
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout &lt;&lt; &quot;type_A thread&quot; &lt;&lt; '\n';
        }
    }

    void stop() {
        halt = true;
    }

private:
    std::atomic&lt;bool&gt; halt;
};
struct type_b {
    type_b() {
        std::cout &lt;&lt; &quot;constructor type_B&quot; &lt;&lt; '\n';
        halt = false;
    }

    void run() {
        while (!halt) {
            std::this_thread::sleep_for(std::chrono::milliseconds(600));
            std::cout &lt;&lt; &quot;type_B thread&quot; &lt;&lt; '\n';
        }
    }

    void stop() {
        halt = true;
    }

private:
    std::atomic&lt;bool&gt; halt;
};
int _tmain(int argc, _TCHAR* argv[])
{
    type_a a;
    type_b b;

    service2(&amp;type_a::stop, &amp;type_a::run, a);
    std::this_thread::sleep_for(std::chrono::seconds(5));

    service2(&amp;type_b::stop, &amp;type_b::run, b);
    std::this_thread::sleep_for(std::chrono::seconds(5));

    return 0;
}
</code></pre>
<p>Nochmals zum Ziel: <code>service2</code> soll moeglichst mit <code>service2(stop_fn, run_fun, obj, param, ...)</code> aufgerufen werden, wobei stop_fn und run_fn Memberfunktionen von obj sind. obj und param... sollen an <code>std::thread</code> uebergeben werden, obj soll nicht gemoved werden, da ich mit dem Objekt gern noch von aussen arbeiten moechte. Die Erweiterung auf Variadic Templates mittels <code>param...</code> ist erstmal icht wichtig, da Visual Studio 11 Beta die nicht unterstuetzt.</p>
<p>PS: Performance ist nicht so wichtig, da <code>stop</code> und <code>start</code> nur jeweils einmal aufgerufen werden sollen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220926</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220926</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Fri, 08 Jun 2012 08:41:55 GMT</pubDate></item><item><title><![CDATA[Reply to Threads, Member Function Pointer und Type Erasure on Fri, 08 Jun 2012 09:34:59 GMT]]></title><description><![CDATA[<blockquote>
<p>gleich nach dem Konstruktor der Destruktor aufgerufen</p>
</blockquote>
<p>Ich Dummbatzen. Natuerlich muss ich auch ein Objekt benennen, also <code>service2 s(...)</code> , da sonst nur ein temporaeres Objekt erzeugt und gleich wieder vernichtet wird. Mittlerweile funktioniert alles wie gewuenscht, wobei ich den Ansatz mit <code>std::function</code> noch untersuchen werde. Danke!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2220941</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2220941</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Fri, 08 Jun 2012 09:34:59 GMT</pubDate></item></channel></rss>