<?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[Min und max für zwei Template Argumente, constexpr]]></title><description><![CDATA[<p>In der STL ist max z.B. folgendermaßen definiert:</p>
<pre><code>template &lt;class T&gt; constexpr const T&amp; max (const T&amp; a, const T&amp; b);
</code></pre>
<p>Was aber nun, wenn ich ein max((char)1, (int)-573) bestimmen möchte?<br />
Dann sind die Template Argumente von verschiedenen Typen und man kommt nicht weiter.</p>
<p>Daher hab ich mir folgendes überlegt:</p>
<pre><code>template &lt;class T1, class T2&gt;
constexpr auto max(const T1 &amp;a, const T2 &amp;b) -&gt; decltype(a&lt;b?b:a){
   return a&lt;b?b:a;
}
</code></pre>
<p>Kann das funktionieren?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/334500/min-und-max-für-zwei-template-argumente-constexpr</link><generator>RSS for Node</generator><lastBuildDate>Sat, 25 Apr 2026 12:11:57 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/334500.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 17 Sep 2015 19:47:11 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Thu, 17 Sep 2015 19:47:11 GMT]]></title><description><![CDATA[<p>In der STL ist max z.B. folgendermaßen definiert:</p>
<pre><code>template &lt;class T&gt; constexpr const T&amp; max (const T&amp; a, const T&amp; b);
</code></pre>
<p>Was aber nun, wenn ich ein max((char)1, (int)-573) bestimmen möchte?<br />
Dann sind die Template Argumente von verschiedenen Typen und man kommt nicht weiter.</p>
<p>Daher hab ich mir folgendes überlegt:</p>
<pre><code>template &lt;class T1, class T2&gt;
constexpr auto max(const T1 &amp;a, const T2 &amp;b) -&gt; decltype(a&lt;b?b:a){
   return a&lt;b?b:a;
}
</code></pre>
<p>Kann das funktionieren?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468345</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468345</guid><dc:creator><![CDATA[MC78]]></dc:creator><pubDate>Thu, 17 Sep 2015 19:47:11 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Thu, 17 Sep 2015 21:54:57 GMT]]></title><description><![CDATA[<p>Ich nehme an, dass der Compiler etwas dazu sagt.</p>
<p>Welchen Zweck soll das Template denn haben? 1 und -375 wirst du ja auch so hinkriegen ...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468353</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468353</guid><dc:creator><![CDATA[manni66]]></dc:creator><pubDate>Thu, 17 Sep 2015 21:54:57 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Fri, 18 Sep 2015 09:48:07 GMT]]></title><description><![CDATA[<p>In c++ definiert</p>
<p>const typ name;</p>
<p>tatsächlich eine compile-time Konstante im Gegensatz zu c.<br />
Die definierten Konstanten können natürlich sowohl negativ als auch positiv sein.<br />
Jetzt kann es allgemein natürlich vorkommen, dass man das Max/Min einer Konstanten und der Summe zweier anderer zur Kompilierzeit bestimmen möchte.<br />
Je nach Vorzeichen und Wert der Konstanten kann sich ein Vergleich zwischen unsigned/unsigned, unsigned/int oder int/int ergeben.<br />
Natürlich soll das Template alle Möglichkeiten erschlagen können.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468381</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468381</guid><dc:creator><![CDATA[MC78]]></dc:creator><pubDate>Fri, 18 Sep 2015 09:48:07 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Fri, 18 Sep 2015 10:31:27 GMT]]></title><description><![CDATA[<p>Was ist jetzt die Frage? Dein Code compiliert jedenfalls. Wunderst du dich vielleicht über den Typ des Rückgabewerts? Da der Rückgabewert zur Compilezeit feststehen muss kann dieser natürlich nicht von den Parametern abhängen. Wenn bei dem Ternären Operator der zweite und dritte Operand einen unterschiedlichen Typ haben hat der gesamte Ausdruck den &quot;Common Type&quot; beider Operanden. Common Type ist der Typ in den man beide Typen implizit konvertieren kann. Das kann manchmal aber auch nicht der Typ sein den man sich wünscht. Wenn ich mir z.B. <code>max((unsigned int)1, (int)-573)</code> ausgeben lasse erhalte ich 4294966723, weil der int Wert zu unsigned konvertiert wird.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468385</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468385</guid><dc:creator><![CDATA[sebi707]]></dc:creator><pubDate>Fri, 18 Sep 2015 10:31:27 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Sat, 19 Sep 2015 06:44:33 GMT]]></title><description><![CDATA[<p>Ja, das ist das Problem. Die Kombi Int/UInt sollte natürlich im Ergebnis<br />
als long int rauskommen, weil das der common-type ist, in dem beide Eingaben darstellbar sind. Die implizierte Konvertierung zu unsigned ist natürlich quatsch, die müsste man irgendwie abstellen. Die Definition von common-type passt für diesen Fall offensichtlich nicht, weil int eben nicht einfach zu unsigned konvertiert werden kann auch wenn man es gerne so hinschreibt.<br />
Die Instantierung des Templates für eine bestimmte Kombination von Eingabetypen soll natürlich auch den folgerichtigen Ausgabetyp beinhalten, was zur Kompilierzeit durchaus prinzipiell festgestellt werden kann.</p>
<p>Die Frage ist, wie kann ich also allgemeingültig die richtige Konvertierung in den Ergebnistyp vornehmen lassen, ohne mich mit einer Template Speziaisierung für sämliche problematischen Sonderfälle herumschlagen zu müssen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468463</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468463</guid><dc:creator><![CDATA[MC78]]></dc:creator><pubDate>Sat, 19 Sep 2015 06:44:33 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Sat, 19 Sep 2015 12:57:39 GMT]]></title><description><![CDATA[<p>MC78 schrieb:</p>
<blockquote>
<p>Ja, das ist das Problem. Die Kombi Int/UInt sollte natürlich im Ergebnis<br />
als long int rauskommen, weil das der common-type ist, in dem beide Eingaben darstellbar sind.</p>
</blockquote>
<p>Es gibt nur einen common-type, und das ist der, der durch die gewöhnlichen arithmetischen Konvertierungen entsteht (und hier nicht immer der richtige ist).<br />
Wenn man will, kann man durch Fallunterscheidung immer zu einem vernünftigen Ergebnis kommen. Ob das in Fällen mit gemischten vorzeichenbehaften/vorzeichenlosen Zahlen allerdings sinnvoll ist, darf bezweifelt werden. Weil eben nicht immer unmittelbar erkennbar ist, ob das Ergebnis nun vorzeichenbehaftet ist oder nicht.<br />
Zu Illustration schnell mal etwas <a href="http://ideone.com/rRUyRj" rel="nofollow">gebastelt</a>:</p>
<pre><code class="language-cpp">#include &lt;limits&gt;
#include &lt;type_traits&gt;
#include &lt;algorithm&gt;

using std::min;
using std::max;

template &lt;typename T&gt;
constexpr auto digits = std::numeric_limits&lt;T&gt;::digits;

template &lt;typename T, typename U, std::enable_if_t&lt;std::is_unsigned&lt;T&gt;{} &amp;&amp; std::is_unsigned&lt;U&gt;{} &amp;&amp; !std::is_same&lt;T, U&gt;{}, int&gt; = 0&gt; // unsigned, unsigned
constexpr auto min(T t, U u)
{
    using result_t = std::conditional_t&lt;digits&lt;U&gt; &lt; digits&lt;T&gt;, U, T&gt;;                                                                 // kleinerer Typ
    return u &lt; t ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}
template &lt;typename T, typename U, std::enable_if_t&lt;std::is_signed&lt;T&gt;{} &amp;&amp; std::is_signed&lt;U&gt;{} &amp;&amp; !std::is_same&lt;T, U&gt;{}, int&gt; = 0&gt;     // signed, signed
constexpr auto min(T t, U u)
{
    using result_t = std::conditional_t&lt;digits&lt;T&gt; &lt; digits&lt;U&gt;, U, T&gt;;                                                                 // größerer Typ
    return u &lt; t ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}
template &lt;typename T, typename U, std::enable_if_t&lt;std::is_unsigned&lt;T&gt;{} &amp;&amp; std::is_signed&lt;U&gt;{}, int&gt; = 0&gt;                            // unsigned, signed
constexpr auto min(T t, U u)
{
    using result_t = U;
    return u &lt; 0 || static_cast&lt;std::make_unsigned_t&lt;U&gt;&gt;(u) &lt; t ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}
template &lt;typename T, typename U, std::enable_if_t&lt;std::is_signed&lt;T&gt;{} &amp;&amp; std::is_unsigned&lt;U&gt;{}, int&gt; = 0&gt;                            // signed, unsigned
constexpr auto min(T t, U u)
{
    using result_t = T;
    return t &gt; 0 &amp;&amp; u &lt; static_cast&lt;std::make_unsigned_t&lt;T&gt;&gt;(t) ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}

template &lt;typename T, typename U, std::enable_if_t&lt;std::is_unsigned&lt;T&gt;{} == std::is_unsigned&lt;U&gt;{} &amp;&amp; !std::is_same&lt;T, U&gt;{}, int&gt; = 0&gt; // unsigned, unsigned oder signed, signed
constexpr auto max(T t, U u)
{
    using result_t = std::conditional_t&lt;digits&lt;U&gt; &lt; digits&lt;T&gt;, U, T&gt;;                                                                 // größerer Typ
    return u &lt; t ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}
template &lt;typename T, typename U, std::enable_if_t&lt;std::is_unsigned&lt;T&gt;{} &amp;&amp; std::is_signed&lt;U&gt;{}, int&gt; = 0&gt;                            // unsigned, signed
constexpr auto max(T t, U u)
{
    using result_t = std::conditional_t&lt;digits&lt;T&gt; &lt; digits&lt;std::make_unsigned_t&lt;U&gt;&gt;, std::make_unsigned_t&lt;U&gt;, T&gt;;
    return u &gt;= 0 &amp;&amp; t &lt; static_cast&lt;std::make_unsigned_t&lt;U&gt;&gt;(u) ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}
template &lt;typename T, typename U, std::enable_if_t&lt;std::is_signed&lt;T&gt;{} &amp;&amp; std::is_unsigned&lt;U&gt;{}, int&gt; = 0&gt;                            // signed, unsigned
constexpr auto max(T t, U u)
{
    using result_t = std::conditional_t&lt;digits&lt;U&gt; &lt; digits&lt;std::make_unsigned_t&lt;T&gt;&gt;, std::make_unsigned_t&lt;T&gt;, U&gt;;
    return t &lt; 0 || static_cast&lt;std::make_unsigned_t&lt;T&gt;&gt;(t) &lt; u ? static_cast&lt;result_t&gt;(u) : static_cast&lt;result_t&gt;(t);
}

int main()
{
	constexpr char c = 1;
	constexpr unsigned short us = 2;
	constexpr int i = 3;
	constexpr long long ll = 4;
	constexpr unsigned long long ull = 5;
	static_assert( min( c, us ) == 1, &quot;&quot; );
	static_assert( std::is_same&lt;decltype(min( c, us )), char&gt;{}, &quot;&quot; );
	static_assert( max( c, us ) == 2, &quot;&quot; );
	static_assert( std::is_same&lt;decltype(max( c, us )), unsigned short&gt;{}, &quot;&quot; );
	static_assert( min( ll, ull ) == 4, &quot;&quot; );
	static_assert( std::is_same&lt;decltype(min( ll, ull )), long long&gt;{}, &quot;&quot; );
	static_assert( max( ll, ull ) == 5, &quot;&quot; );
	static_assert( std::is_same&lt;decltype(max( ll, ull )), unsigned long long&gt;{}, &quot;&quot; );
}
</code></pre>
<p>float-Zahlen müssten man noch separat behandeln, und von gemischten integer/floats lässt man am Besten gleich die Finger.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468480</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468480</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Sat, 19 Sep 2015 12:57:39 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Sat, 19 Sep 2015 11:56:25 GMT]]></title><description><![CDATA[<p>MC78 schrieb:</p>
<blockquote>
<p>Die Instantierung des Templates für eine bestimmte Kombination von Eingabetypen soll natürlich auch den folgerichtigen Ausgabetyp beinhalten, was zur Kompilierzeit durchaus prinzipiell festgestellt werden kann.</p>
</blockquote>
<p>Das ist natürlich machbar. Allerdings würde für dein Problem der Rückgabetyp idealerweise vom Ergebnis des Vergleichs abhängen und das geht meines Wissens nicht (bin aber kein constexpr Experte). Und deine Definition von Common Type funktioniert nicht für alle Typen. Bei Integer möchtest du ja den nächst größeren Typ nehmen aber was wenn man ein uint64_t mit int64_t vergleicht? Einen int128_t gibt es wohl bei den wenigsten Compilern. Oder was ist nach deiner Defintion der Common Type von int und float? Bei int zu float geht eventuell Genauigkeit verloren wenn der int Wert recht groß ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468481</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468481</guid><dc:creator><![CDATA[sebi707]]></dc:creator><pubDate>Sat, 19 Sep 2015 11:56:25 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Mon, 21 Sep 2015 13:15:21 GMT]]></title><description><![CDATA[<p>Obige Implementierung nutzt die teilweise sinnvollen UACs nicht aus, und produziert u.U. andere Typen (was AFAICS völlig unnötig ist, da so die Anzahl nachträglicher Konvertierungen des Rückgabewerts insg. nicht vermindert wird). Folgendes ist IMO besser:</p>
<pre><code>#include &lt;limits&gt;
#include &lt;type_traits&gt;

template &lt;typename T, typename U&gt;
using max_t = std::conditional_t&lt;std::numeric_limits&lt;T&gt;::max()    &lt; std::numeric_limits&lt;U&gt;::max()   , U, T&gt;;
template &lt;typename T, typename U&gt;
using min_t = std::conditional_t&lt;std::numeric_limits&lt;T&gt;::min()/-2 &lt; std::numeric_limits&lt;U&gt;::min()/-2, U, T&gt;;

template &lt;typename T, typename U&gt;
constexpr auto min(T t, U u) {
    return (u &lt; 0 &amp;&amp; std::is_unsigned&lt;T&gt;{}) || ((t &gt;= 0 || std::is_signed&lt;U&gt;{}) &amp;&amp; (min_t&lt;T, U&gt;)u &lt; (min_t&lt;T, U&gt;)t)?
        (min_t&lt;T, U&gt;)u : (min_t&lt;T, U&gt;)t;
}
template &lt;typename T, typename U&gt; 
constexpr max_t&lt;T, U&gt; max(T t, U u) {
    return (t &lt; 0 &amp;&amp; std::is_unsigned&lt;U&gt;{}) || ((u &gt;= 0 || std::is_signed&lt;T&gt;{}) &amp;&amp; (max_t&lt;T, U&gt;)t &lt; (max_t&lt;T, U&gt;)u)? u : t;
}

#define CHECK_(f, t, u, R, r) static_assert( f(t,u) == r &amp;&amp; std::is_same&lt;decltype(f(t,u)),R&gt;{}, &quot;&quot; );
#define CHECK(t, u, R1, R2) CHECK_(min, t, u, R1, t) CHECK_(max, t, u, R2, u)
CHECK((char)-1, (unsigned short)2, char, unsigned short)
CHECK((short)30000, (int)5641761, int, int)
CHECK((long long)-651465154, (unsigned)-1, long long, long long)
CHECK((unsigned)0, (int)1, int, unsigned)
</code></pre>
<p>Kompiliert <a href="http://coliru.stacked-crooked.com/a/5c2aa882ae3de63d" rel="nofollow">ohne Warnungen</a> (dafür waren die prinzipiell überflüssigen Casts im Vergleich nötig).</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468628</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468628</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Mon, 21 Sep 2015 13:15:21 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Mon, 21 Sep 2015 13:25:49 GMT]]></title><description><![CDATA[<blockquote>
<p>Bei Integer möchtest du ja den nächst größeren Typ nehmen aber was wenn man ein uint64_t mit int64_t vergleicht?</p>
</blockquote>
<p>Hier besteht kein Problem. Wir wissen bei <code>min</code> , dass wir entweder eine negative Zahl als Minimum zurückgeben, oder zwei positive Zahlen vergleichen müssen, in welchem Falle wir den vom vorzeichenbehafteten Typ gespeicherten Wert zum anderen konvertieren. Bei <code>max</code> ist die Argumentation ähnlich. Natürlich setzt das Ganze ggf. zwei Vergleiche voraus, aber der eine ist zum Glück trivial.</p>
<p>Für gewöhnlich hat man jedoch schon irgendeine Art von Information über die Werte (e.g. der im vorzeichenbehafteten Typ ist positiv), daher sind solche min/max Dinger nur in Spezialfällen nötig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468629</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468629</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Mon, 21 Sep 2015 13:25:49 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Mon, 21 Sep 2015 19:12:12 GMT]]></title><description><![CDATA[<p>Vielen lieben Dank für die Antworten. Ich glaube ich hab unterschätzt, was die Frage für einen Rattenschwanz hinter sich herzieht.</p>
<p>Ich glaube, die Antwort von Arcoth halbwegs kapiert zu haben.<br />
Mit conditional_t wählt man je nachdem, ob der größte darstellbare Wert von T oder U größer ist T oder U als Typ für max_t aus.<br />
Für die vorzeichenbehafteten Zahlen sollte ja std::numeric_limits&lt;...&gt;::max() kleiner sein, als für die ohne Vorzeichen.<br />
Mit diesem max_t als Rückgabewert für das max Template umgeht man die Probleme mit der implizierten Konvertierung.<br />
Was mir nicht so klar ist: Warum muss man das bei dem min Template nicht analog machen? <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>Beim vorherigen Post von Camper habe ich mich leider etwas abgehängt gefühlt.</p>
<p><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/2468668</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468668</guid><dc:creator><![CDATA[MC78]]></dc:creator><pubDate>Mon, 21 Sep 2015 19:12:12 GMT</pubDate></item><item><title><![CDATA[Reply to Min und max für zwei Template Argumente, constexpr on Mon, 21 Sep 2015 20:28:19 GMT]]></title><description><![CDATA[<p>MC78 schrieb:</p>
<blockquote>
<p>Beim vorherigen Post von Camper habe ich mich leider etwas abgehängt gefühlt.</p>
</blockquote>
<p>ja, das war unnötig umständlich.</p>
<p>Arcoth schrieb:</p>
<blockquote>
<p>produziert u.U. andere Typen</p>
</blockquote>
<p>Passiert, wenn man Code ohne gross nachzudenken aus den Fingern saugt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /><br />
Hatte mir irgendwie Fälle zusammengereimt, wo weder T noch U passen, ist aber Unfug.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2468673</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2468673</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 21 Sep 2015 20:28:19 GMT</pubDate></item></channel></rss>