<?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[templates, implizite konvertierung]]></title><description><![CDATA[<p>hallo,<br />
ich habe folgende klasse<br />
(in etwa)</p>
<pre><code class="language-cpp">template &lt;class T&gt;
class Vector
{
}
</code></pre>
<p>kann mir wer sagen, wie ich eine implizite konvertierung von<br />
folgenden vectoren schreiben kann? (und zwar nur für diese)</p>
<p>int -&gt; double<br />
float -&gt; double</p>
<p>usw, also eigentlich für alle, bei denen keine information verloren geht.<br />
Ich weiss das man es mit überschreibung von operator() machen müsste,<br />
aber wegen der template sache bekomme ich das irgendwie nicht hin <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/topic/200836/templates-implizite-konvertierung</link><generator>RSS for Node</generator><lastBuildDate>Mon, 05 Oct 2026 06:05:26 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/200836.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 20 Dec 2007 10:44:38 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to templates, implizite konvertierung on Thu, 20 Dec 2007 10:44:38 GMT]]></title><description><![CDATA[<p>hallo,<br />
ich habe folgende klasse<br />
(in etwa)</p>
<pre><code class="language-cpp">template &lt;class T&gt;
class Vector
{
}
</code></pre>
<p>kann mir wer sagen, wie ich eine implizite konvertierung von<br />
folgenden vectoren schreiben kann? (und zwar nur für diese)</p>
<p>int -&gt; double<br />
float -&gt; double</p>
<p>usw, also eigentlich für alle, bei denen keine information verloren geht.<br />
Ich weiss das man es mit überschreibung von operator() machen müsste,<br />
aber wegen der template sache bekomme ich das irgendwie nicht hin <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1423660</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1423660</guid><dc:creator><![CDATA[Treb]]></dc:creator><pubDate>Thu, 20 Dec 2007 10:44:38 GMT</pubDate></item><item><title><![CDATA[Reply to templates, implizite konvertierung on Thu, 20 Dec 2007 10:50:53 GMT]]></title><description><![CDATA[<p>Da mußt du Spezialisierungen für Vector&lt;double&gt; schreiben, die diese Konvertierungen anbieten.</p>
<p>Wenn die Klasse viel Code hat, würde ich den gemeinsamen Anteil seperat halten - Template-Spezialisierungen &quot;erben&quot; nicht die Methoden der Grundversion:</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
class Vector_base
{
  ...
};

template&lt;typename T&gt;
class Vector : public Vector_base&lt;T&gt;
{
  //muß nur die Ctor'en überschreiben - darum kommst du nicht herum
};

template&lt;&gt;
class Vector&lt;double&gt; : public Vector_base&lt;double&gt;
{
public:
  //Umwandlungs-Konstruktoren:
  Vector(const Vector&lt;int&gt;&amp;);
  Vector(const Vector&lt;float&gt;&amp;);

  //außerdem noch die allgemeinen Konstruktoren aus der Vector&lt;&gt;
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1423663</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1423663</guid><dc:creator><![CDATA[CStoll]]></dc:creator><pubDate>Thu, 20 Dec 2007 10:50:53 GMT</pubDate></item><item><title><![CDATA[Reply to templates, implizite konvertierung on Thu, 20 Dec 2007 13:21:34 GMT]]></title><description><![CDATA[<p>CStoll schrieb:</p>
<blockquote>
<p>Da mußt du Spezialisierungen für Vector&lt;double&gt; schreiben, die diese Konvertierungen anbieten.</p>
<p>Wenn die Klasse viel Code hat, würde ich den gemeinsamen Anteil seperat halten - Template-Spezialisierungen &quot;erben&quot; nicht die Methoden der Grundversion:</p>
<pre><code class="language-cpp">...
</code></pre>
</blockquote>
<p>Das ist eine Möglichkeit, man endet aber trotzdem mit einer großen Menge an Duplizität, die nichts mit dem Problem zu tun hat. Besser ist die eigentliche Konvertierung außerhalb der Klasse durchzuführen, irgendwelche Spezialisierungen führen dann nicht zu extra Aufwand im Vektor-Temnplate. Was wir brauchen, ist eine Konvertierungsfunktion, die verschiedene Vektoren als Argument nimmt, wobei bestimmte zusätzliche Bedingungen an den Templateparameter gestellt werden:</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
class Vector
{
    template&lt;typename U&gt;
    Vector(const Vector&lt;U&gt;&amp; other);
}
</code></pre>
<p>Für ungültige Kombinationen aus T und U soll diese Konvertierung unterdrückt werden. Dabei haben wir zwei Möglichkeiten:<br />
1. wir lassen die Funktion so stehen, und machen sie für ungültige Paarungen nicht instantiierbar<br />
2. wir unterdrücken solche Paarungen mit SFINAE<br />
Variante 1 ist zweifellos verständlicher für den Templateschreiber, hat aber den Nachteil, das der Vektor dann immer noch als konvertierbar für solche Paarungen gilt (is_convertible und ähnliche Metatemplatefunktionen machen dann Ärger).</p>
<p>Zum Eingemachten: wir verlagern die eigentliche Konvertierung in ein eigenes Template und spezialisieren geeignet:</p>
<pre><code class="language-cpp">template&lt;typename T, typename U&gt;
struct Convert
{
    static const bool value = true;
    T convert(U x) const { return static_cast&lt;T&gt;(x); }
};

template&lt;typename T, typename U&gt;
struct SafeConvert
{
    static const bool value = false;
};
// jetzt die Spezialisierungen, das ist immer noch eine Menge Arbeit
template&lt;&gt; struct SafeConvert&lt; int, long &gt; : Convert&lt; int, long &gt; {};
template&lt;&gt; struct SafeConvert&lt; int, double &gt; : Convert&lt; int, double &gt; {};
template&lt;&gt; struct SafeConvert&lt; float, double &gt; : Convert&lt; float, double &gt; {};
// usw.

template&lt;typename T&gt; template&lt;typename U&gt; Vector&lt;T&gt;::Vector(const Vector&lt;U&gt;&amp; other)
{
    // für jedes einzelne Element SafeConvert&lt;T,U&gt;().convert aufrufen...
}
</code></pre>
<p>Das Ganze mit SFINAE wird nur wenig komplizierter (da ich SafeConvert schon vorbereitet habe):</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
class Vector
{
    template&lt;typename U&gt;
    Vector(const Vector&lt;U&gt;&amp; other, typename enable_if&lt;SafeConvert&lt;T,U&gt; &gt;::type* = 0);
}
</code></pre>
<p>Die Wiederholungen beschränken sich jetzt auf die Nennung aller gültigen Paarungen. Aber auch das ist eigentlich unnötiger Aufwand und skaliert nicht gut, insbesondere, wenn das Ganze für eigene Typen erweiterbar sein soll.<br />
Mittels std::numerc_limits können wir das besser machen:<br />
Ein Konvertierung ist sicher, wenn:<br />
- beide Typen integer sind, und beide vorzeichenbehaftet sind und der Zieltyp nicht weniger Stellen besitzt, oder<br />
- beide Typen integer sind, und die Quelle vorzeichenlos ist und der Zieltyp nicht weniger Stellen besitzt, oder<br />
- die Quelle ein Integer und das Ziel ein Gleitkommatyp ist, und der der Gleitkommatyp hinreichen viele signifikante Stellen besitzt, oder<br />
- beide Gleitkommatypen sind, und der Zieltyp in signifikanten Stellen und Stellen der Mantisse nicht geringer als die Quelle ist:</p>
<pre><code class="language-cpp">template&lt;typename T, typename U&gt;
struct SafeConvert
{
    typedef std::numeric_limits&lt;T&gt; src;
    typedef std::numeric_limits&lt;U&gt; dest;
    static const bool value = src::is_specialized &amp;&amp; dest::is_specialised &amp;&amp; src::radix == dest::radix &amp;&amp;
        ( ( src::is_integer &amp;&amp; dest::is_integer &amp;&amp; src::digits &lt;= dest::digits &amp;&amp; !( src::is_signed &amp;&amp; !dest::is_signed ) )
        || ( src::is_integer &amp;&amp; !dest::is_integer &amp;&amp; src::digits &lt;= dest::digits )
        || ( !src::is_integer &amp;&amp; !dest::is_integer &amp;&amp; src::digits &lt;= dest::digits &amp;&amp; src::min_exponent &gt;= dest::min_exponent &amp;&amp; src::max_exponent &lt;= dest::max_exponent ) )
    T convert(U x) const { return static_cast&lt;T&gt;(x); }
};
</code></pre>
<p>Das kann man noch etwas besser machen (ich war jetzt zu faul, mit unterschiedlichen Darstellungen (radix) und exakten gebrochenen Zahlen (rational) oder erweiterten Zahlenbereichen (complex) umzugehen. Zweifellos ist es so aber am wenigsten Schreibarbeit - erfordert aber eben erst einmal ein bisschen nachdenken statt stupides C&amp;P <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>
]]></description><link>https://www.c-plusplus.net/forum/post/1423792</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1423792</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Thu, 20 Dec 2007 13:21:34 GMT</pubDate></item></channel></rss>