<?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[[Erledigt] boost::enable_if, Vermeiden von Codeduplikation]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich stehe gerade auf dem Schlauch. Ich möchte eine Iterator-Klasse implementieren, allerdings brauche ich die einmal in der normalen und einmal als 'const_iterator'-Variante. Um Codeduplikation zu vermeiden, habe ich die Klasse einfach als Template geschrieben und dann zwei Typedefs definiert (der Iterator selbst ist nur ein recht einfacher Wrapper um einen anderen Iterator).</p>
<p>Allerdings braucht die const-Version einen zusätzlichen Konstruktor, der die Initialisierung durch Konvertierung von einem non-const-Objekt erlaubt. Spezialisierung klappt nicht (oder kann ich dann den anderen Code „erben“?). Also dachte ich an 'boost::enable_if, obwohl der Konstruktor dann ein zweites Dummy-Argument hätte, was ich nicht besonders schick finde.</p>
<p>… leider klappt das nicht so, wie ich will. Der Compiler (MSVC9) beschwert sich, „'type': is not a member of 'boost::enable_if&lt;Cond&gt;'“; bei folgendem Code:</p>
<pre><code class="language-cpp">template &lt;typename ListIter&gt;
class list_iterator
    : public std::iterator&lt; /* … */&gt; {
public:

    list_iterator() : m_nodeptr() { }

    list_iterator(ListIter nodeptr) : m_nodeptr(nodeptr) { }

    list_iterator(
        list_iterator&lt;node_iterator&gt; const&amp; other,
        typename boost::enable_if&lt;
            typename boost::template is_same&lt;ListIter, const_node_iterator&gt;::type
        &gt;::type* dummy = 0
    ) : m_nodeptr(other.nodeptr()) { }
};
</code></pre>
<p>('m_nodeptr' bzw. 'nodeptr()' sind entsprechend definierte Mitglieder.)</p>
<p>'node_iterator' bzw 'const_node_iterator' sind dabei wie folgt definiert:</p>
<pre><code class="language-cpp">typedef std::list&lt;
    node, typename allocator_type::template rebind&lt;node&gt;::other
&gt;                                               list_type;
typedef typename list_type::iterator            node_iterator;
typedef typename list_type::const_iterator      const_node_iterator;
</code></pre>
<p>Ich habe 'boost::enable_if' bisher noch nie benutzt und SFINAE selbst auch nur sehr wenig. Ich denke daher, dass das ein grundsätzlicher Fehler ist, oder?</p>
<p>(Langsam beginne ich zu denken, dass es wesentlich wartbarer wäre, die zwei Iterator-Typen getrennt doppelt zu implementieren.)</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/202738/erledigt-boost-enable_if-vermeiden-von-codeduplikation</link><generator>RSS for Node</generator><lastBuildDate>Tue, 06 Oct 2026 23:03:24 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/202738.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 14 Jan 2008 22:01:54 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 07:31:47 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>ich stehe gerade auf dem Schlauch. Ich möchte eine Iterator-Klasse implementieren, allerdings brauche ich die einmal in der normalen und einmal als 'const_iterator'-Variante. Um Codeduplikation zu vermeiden, habe ich die Klasse einfach als Template geschrieben und dann zwei Typedefs definiert (der Iterator selbst ist nur ein recht einfacher Wrapper um einen anderen Iterator).</p>
<p>Allerdings braucht die const-Version einen zusätzlichen Konstruktor, der die Initialisierung durch Konvertierung von einem non-const-Objekt erlaubt. Spezialisierung klappt nicht (oder kann ich dann den anderen Code „erben“?). Also dachte ich an 'boost::enable_if, obwohl der Konstruktor dann ein zweites Dummy-Argument hätte, was ich nicht besonders schick finde.</p>
<p>… leider klappt das nicht so, wie ich will. Der Compiler (MSVC9) beschwert sich, „'type': is not a member of 'boost::enable_if&lt;Cond&gt;'“; bei folgendem Code:</p>
<pre><code class="language-cpp">template &lt;typename ListIter&gt;
class list_iterator
    : public std::iterator&lt; /* … */&gt; {
public:

    list_iterator() : m_nodeptr() { }

    list_iterator(ListIter nodeptr) : m_nodeptr(nodeptr) { }

    list_iterator(
        list_iterator&lt;node_iterator&gt; const&amp; other,
        typename boost::enable_if&lt;
            typename boost::template is_same&lt;ListIter, const_node_iterator&gt;::type
        &gt;::type* dummy = 0
    ) : m_nodeptr(other.nodeptr()) { }
};
</code></pre>
<p>('m_nodeptr' bzw. 'nodeptr()' sind entsprechend definierte Mitglieder.)</p>
<p>'node_iterator' bzw 'const_node_iterator' sind dabei wie folgt definiert:</p>
<pre><code class="language-cpp">typedef std::list&lt;
    node, typename allocator_type::template rebind&lt;node&gt;::other
&gt;                                               list_type;
typedef typename list_type::iterator            node_iterator;
typedef typename list_type::const_iterator      const_node_iterator;
</code></pre>
<p>Ich habe 'boost::enable_if' bisher noch nie benutzt und SFINAE selbst auch nur sehr wenig. Ich denke daher, dass das ein grundsätzlicher Fehler ist, oder?</p>
<p>(Langsam beginne ich zu denken, dass es wesentlich wartbarer wäre, die zwei Iterator-Typen getrennt doppelt zu implementieren.)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436704</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436704</guid><dc:creator><![CDATA[Konrad Rudolph]]></dc:creator><pubDate>Tue, 15 Jan 2008 07:31:47 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Mon, 14 Jan 2008 23:23:16 GMT]]></title><description><![CDATA[<p>explizite spezialisierung ist keine lösung?</p>
<pre><code class="language-cpp">template &lt;&gt;
class list_iterator&lt;node_iterator&gt; :: list_iterator ( list_iterator&lt;node_iterator&gt; const&amp; other )
{
//= copy ctor
}

template &lt;&gt;
class list_iterator&lt;const_node_iterator&gt;::list_iterator ( list_iterator&lt;node_iterator&gt; const&amp; other )
{
//= what you want
}

//copy ctor für list_iterator&lt;const_node_iterator&gt; wird automatisch erstellt
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1436717</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436717</guid><dc:creator><![CDATA[queer_boy]]></dc:creator><pubDate>Mon, 14 Jan 2008 23:23:16 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 00:03:15 GMT]]></title><description><![CDATA[<p>Der Konstruktor list_iterator ist zwar Member eines Templates, aber selbst eine normale Funktion, SFINAE bezieht sich aber nur auf Funktionstemplates. boost::is_same ist übrigens kein abhänger Name, das Schlüsselwort template hat dort nichts verloren, und is_same ist bereits eine Metafunktion, wie enable_if sie benötigt, das ::type kann man sich also sparen.</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
    list_iterator(
        list_iterator&lt;T&gt; const&amp; other,
        typename boost::enable_if_c&lt;
            boost::is_same&lt;T, node_iterator&gt;::value
            &amp;&amp; boost::is_same&lt;ListIter, const_node_iterator&gt;::value
        &gt;::type* dummy = 0
    ) : m_nodeptr(other.nodeptr()) { }
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1436721</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436721</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 15 Jan 2008 00:03:15 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 01:31:46 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>boost::is_same ist übrigens kein abhänger Name, das Schlüsselwort template hat dort nichts verloren,</p>
</blockquote>
<p>richtig, aber ich glaube, nicht aus diesem grund.<br />
14.2/5 würde template hier dennoch erlauben, der grund, warum es trotzdem ill-formed ist, ist bloß, weil is_same kein member-template ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436724</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436724</guid><dc:creator><![CDATA[queer_boy]]></dc:creator><pubDate>Tue, 15 Jan 2008 01:31:46 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 02:17:27 GMT]]></title><description><![CDATA[<p>queer_boy schrieb:</p>
<blockquote>
<p>camper schrieb:</p>
<blockquote>
<p>boost::is_same ist übrigens kein abhänger Name, das Schlüsselwort template hat dort nichts verloren,</p>
</blockquote>
<p>richtig, aber ich glaube, nicht aus diesem grund.<br />
14.2/5 würde template hier dennoch erlauben, der grund, warum es trotzdem ill-formed ist, ist bloß, weil is_same kein member-template ist.</p>
</blockquote>
<p>Ja. Allerdings sind typename und template nur bei abhängigen Namen (was Member impliziert) notwendig. Die Vereinfachung der Regel erleichtert das Schreiben in Fällen, wo es nicht auf Anhieb offensichtlich ist, ob ein Name abhängig ist. Von einem inflationären Gebrauch davon - insbesondere mit C++0x - halte ich aber nichts. Eine Stelle, an der diese Schlüsselworte nicht benötigt werden, wird durch sie im Allgemeinen nicht besser werden.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436725</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436725</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 15 Jan 2008 02:17:27 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 07:18:58 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Der Konstruktor list_iterator ist zwar Member eines Templates, aber selbst eine normale Funktion, SFINAE bezieht sich aber nur auf Funktionstemplates.</p>
</blockquote>
<p>Autsch. Logisch.</p>
<blockquote>
<p>boost::is_same ist übrigens kein abhänger Name, das Schlüsselwort template hat dort nichts verloren</p>
</blockquote>
<p>Noch'n Autsch. <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>
<blockquote>
<p>und is_same ist bereits eine Metafunktion, wie enable_if sie benötigt, das ::type kann man sich also sparen.</p>
</blockquote>
<p>Jupp, aber da es ohne nicht funktionierte, habe ich es explizit hingeschrieben, um alle möglichen Fehlerquellen auszuschließen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436752</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436752</guid><dc:creator><![CDATA[Konrad Rudolph]]></dc:creator><pubDate>Tue, 15 Jan 2008 07:18:58 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 07:30:00 GMT]]></title><description><![CDATA[<p>Übrigens:</p>
<p>- Explizite Template-Spezialisierung des Kopierkonstruktors funktioniert nicht. Ich weiß nicht genau wo der Wurm drin ist. Der Compiler meckert, ich würde ein Member definieren, das ich nicht deklariert habe (obwohl ich es sehr wohl deklariert habe).</p>
<p>- Aus dem Kopierkonstruktor ein Template zu machen ist auch keine Lösung. Die Initialisierung wird ja für den folgenden Fall gebraucht, und da wird AFAIK kein Template korrekt hin aufgelöst, oder?</p>
<pre><code class="language-cpp">mycontainer_type mycont;
// ruft die non-const-Version auf.
mycontainer_type::const_iterator = mycont.begin();
</code></pre>
<p>D.h. hier wird implizit konstruiert.</p>
<p>… ist aber alles egal, ich habe es jetzt nochmal mit einer Konvertierungsfunktion versucht und das klappt super. Ohne SFINAE, ohne partielle Spezialisierung:</p>
<pre><code class="language-cpp">operator list_iterator&lt;const_node_iterator&gt; () const {
    return list_iterator&lt;const_node_iterator&gt;(m_nodeptr);
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1436759</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436759</guid><dc:creator><![CDATA[Konrad Rudolph]]></dc:creator><pubDate>Tue, 15 Jan 2008 07:30:00 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 08:07:22 GMT]]></title><description><![CDATA[<p>Konrad Rudolph schrieb:</p>
<blockquote>
<p>Übrigens:</p>
<p>- Explizite Template-Spezialisierung des Kopierkonstruktors funktioniert nicht. Ich weiß nicht genau wo der Wurm drin ist. Der Compiler meckert, ich würde ein Member definieren, das ich nicht deklariert habe (obwohl ich es sehr wohl deklariert habe).</p>
</blockquote>
<p>Der obige Template-ctor ist kein Copy-ctor, zudem ist ja ohnehin nur eine einzige Spezialisierung möglich, wozu diese noch einmal explizit durchführen? Was hast du denn versucht?</p>
<blockquote>
<p>- Aus dem Kopierkonstruktor ein Template zu machen ist auch keine Lösung. Die Initialisierung wird ja für den folgenden Fall gebraucht, und da wird AFAIK kein Template korrekt hin aufgelöst, oder?</p>
</blockquote>
<p>Ein Templatekonstruktor ist niemals ein Copy-ctor. Wieder kann ich nicht ganz folgen.</p>
<blockquote>
<pre><code class="language-cpp">mycontainer_type mycont;
// ruft die non-const-Version auf.
mycontainer_type::const_iterator = mycont.begin();
</code></pre>
</blockquote>
<p>Das sollte (nachdem es korrigiert wurde) eigentlich funktionieren, genau für diesen Fall haben wir uns ja die Mühe gemacht.</p>
<blockquote>
<p>… ist aber alles egal, ich habe es jetzt nochmal mit einer Konvertierungsfunktion versucht und das klappt super. Ohne SFINAE, ohne partielle Spezialisierung:</p>
<pre><code class="language-cpp">operator list_iterator&lt;const_node_iterator&gt; () const {
    return list_iterator&lt;const_node_iterator&gt;(m_nodeptr);
}
</code></pre>
</blockquote>
<p>Das ist natürlich ebenfalls möglich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436779</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436779</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 15 Jan 2008 08:07:22 GMT</pubDate></item><item><title><![CDATA[Reply to [Erledigt] boost::enable_if, Vermeiden von Codeduplikation on Tue, 15 Jan 2008 08:20:20 GMT]]></title><description><![CDATA[<p>camper schrieb:</p>
<blockquote>
<p>Konrad Rudolph schrieb:</p>
<blockquote>
<p>Übrigens:</p>
<p>- Explizite Template-Spezialisierung des Kopierkonstruktors funktioniert nicht. Ich weiß nicht genau wo der Wurm drin ist. Der Compiler meckert, ich würde ein Member definieren, das ich nicht deklariert habe (obwohl ich es sehr wohl deklariert habe).</p>
</blockquote>
<p>Der obige Template-ctor ist kein Copy-ctor</p>
</blockquote>
<p>Ja, schon klar. Ich bezog mich auf den Code von queer_boy. Hierbei ist natürlich ebenfalls nur einer der beiden Konstruktoren ein copycon, der andere nicht. Aber wie queer_boy schrieb, müsste der passende copycon dann doch automatisch erstellt werden.</p>
<blockquote>
<blockquote>
<p>- Aus dem Kopierkonstruktor ein Template zu machen ist auch keine Lösung. Die Initialisierung wird ja für den folgenden Fall gebraucht, und da wird AFAIK kein Template korrekt hin aufgelöst, oder?</p>
</blockquote>
<p>Ein Templatekonstruktor ist niemals ein Copy-ctor.</p>
</blockquote>
<p>Ja, meinte ich mit „ist auch keine Lösung“. Wobei ich übersehen habe, dass das Template bei diesem Konstruktor in der Tat korrekt aufgelöst wird.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1436786</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1436786</guid><dc:creator><![CDATA[Konrad Rudolph]]></dc:creator><pubDate>Tue, 15 Jan 2008 08:20:20 GMT</pubDate></item></channel></rss>