<?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[const einfach]]></title><description><![CDATA[<p>Haltet ihr so etwas für nützlich ?</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
constexpr typename std:conditional&lt;std::is_reference&lt;T&gt;::value, const typename std::remove_reference&lt;T&gt;::type&amp;, const T&amp;&amp;&gt;::type auto_const(T&amp;&amp; x)
{
    return std::forward&lt;T&gt;( x );
}
</code></pre>
<p>Anwendung z.B. in</p>
<pre><code class="language-cpp">vector &lt;int&gt; v = { ... };
for ( auto&amp; x : v )               // vector&lt;int&gt;::iterator
   ;

for ( const auto&amp; x : v )         // vector&lt;int&gt;::iterator, x ist const lvalue
   ;

for ( auto&amp; x : auto_const( v ) ) // vector&lt;int&gt;::const_iterator
   ;

// const Überladung
struct foo
{
    const int&amp; operator[](int x) const;
    int&amp; operator[](int x) { return const_cast&lt;int&amp;&gt;(auto_const(*this)[x]); }
};
</code></pre>
<p>Die Idee ist, den sonst nötigen expliziten aber völlig unkritischen Cast zu vermeiden, in dem auch noch mal explizit der Typ aufgeschrieben werden muss.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/326964/const-einfach</link><generator>RSS for Node</generator><lastBuildDate>Tue, 26 May 2026 06:02:10 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/326964.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 16 Jul 2014 13:05:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to const einfach on Wed, 16 Jul 2014 13:05:07 GMT]]></title><description><![CDATA[<p>Haltet ihr so etwas für nützlich ?</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
constexpr typename std:conditional&lt;std::is_reference&lt;T&gt;::value, const typename std::remove_reference&lt;T&gt;::type&amp;, const T&amp;&amp;&gt;::type auto_const(T&amp;&amp; x)
{
    return std::forward&lt;T&gt;( x );
}
</code></pre>
<p>Anwendung z.B. in</p>
<pre><code class="language-cpp">vector &lt;int&gt; v = { ... };
for ( auto&amp; x : v )               // vector&lt;int&gt;::iterator
   ;

for ( const auto&amp; x : v )         // vector&lt;int&gt;::iterator, x ist const lvalue
   ;

for ( auto&amp; x : auto_const( v ) ) // vector&lt;int&gt;::const_iterator
   ;

// const Überladung
struct foo
{
    const int&amp; operator[](int x) const;
    int&amp; operator[](int x) { return const_cast&lt;int&amp;&gt;(auto_const(*this)[x]); }
};
</code></pre>
<p>Die Idee ist, den sonst nötigen expliziten aber völlig unkritischen Cast zu vermeiden, in dem auch noch mal explizit der Typ aufgeschrieben werden muss.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2408925</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2408925</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Wed, 16 Jul 2014 13:05:07 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Wed, 16 Jul 2014 13:14:18 GMT]]></title><description><![CDATA[<p>Könntest du vielleicht ein wenig mehr dazu schreiben?<br />
Was der Code macht und was das Ziel ist?</p>
<p>Mir persönlich erschließt sich nicht sofort was das Ziel ist, aber ich bin vielleicht auch die falsche Zielgruppe.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2408930</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2408930</guid><dc:creator><![CDATA[chp+]]></dc:creator><pubDate>Wed, 16 Jul 2014 13:14:18 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Wed, 16 Jul 2014 13:28:59 GMT]]></title><description><![CDATA[<pre><code class="language-cpp">for ( const auto&amp; x : v )         // vector&lt;int&gt;::iterator, x ist const lvalue
   ;

for ( auto&amp; x : auto_const( v ) ) // vector&lt;int&gt;::const_iterator
   ;
</code></pre>
<p>Auch wenn das zweite vielleicht theoretisch etwas sauberer ist, ich kann mir nicht vorstellen, dass ein <code>const_iterator</code> schneller ist als ein normaler <code>iterator</code> . Vom Code her gefällt mir die erste Variante besser weil sofort klar ist, dass x const ist und das v nicht verdeckt wird.</p>
<p>Praktisch fände ich das hingegen bei Parameterübergaben.</p>
<pre><code class="language-cpp">std::find(v, 'x'); // wird v hier verändert?
std::find(auto_const(v), 'x'); // hier nicht
// (falls mal endlich Ranges kommen)
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2408935</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2408935</guid><dc:creator><![CDATA[anwendung]]></dc:creator><pubDate>Wed, 16 Jul 2014 13:28:59 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Thu, 17 Jul 2014 07:40:51 GMT]]></title><description><![CDATA[<p>Ist nützlich. Zeiger sind aber stets spaßiger. Erst brauchen wir <code>apply_cv</code> :</p>
<pre><code>template &lt;typename...&gt; struct type_list; // Das kommt einfach mal hierhin

#include &lt;type_traits&gt;

#define DEFINE_ALIAS_T(name)                \
template &lt;typename T, typename U&gt;           \
using name##_t = typename name&lt;T, U&gt;::type;

/// --------------------------------------------------------------------------------------------------------------

template &lt;typename T, typename U&gt; struct apply_const    : std::conditional&lt;std::is_const   &lt;T&gt;::value, U const   , U&gt; {};
template &lt;typename T, typename U&gt; struct apply_volatile : std::conditional&lt;std::is_volatile&lt;T&gt;::value, U volatile, U&gt; {};

DEFINE_ALIAS_T(apply_const)
DEFINE_ALIAS_T(apply_volatile)

template &lt;typename T, typename U&gt; struct apply_cv : apply_const&lt;T, apply_volatile_t&lt;T, U&gt;&gt; {};

DEFINE_ALIAS_T(apply_cv)

/// --------------------------------------------------------------------------------------------------------------

template &lt;typename T, typename U&gt; struct subtract_const    : std::conditional&lt;std::is_const   &lt;T&gt;::value, std::remove_const_t   &lt;U&gt;, U&gt; {};
template &lt;typename T, typename U&gt; struct subtract_volatile : std::conditional&lt;std::is_volatile&lt;T&gt;::value, std::remove_volatile_t&lt;U&gt;, U&gt; {};

DEFINE_ALIAS_T(subtract_const)
DEFINE_ALIAS_T(subtract_volatile)

template &lt;typename T, typename U&gt; struct subtract_cv : subtract_const&lt;T, subtract_volatile_t&lt;T, U&gt;&gt; {};

DEFINE_ALIAS_T(subtract_cv)
</code></pre>
<p>Referenzen können nicht cv-qualifiziert sein, Zeiger schon. Und dann müssen die Veränderungen ja auf vorgebbaren Ebenen stattfinden.</p>
<pre><code>template &lt;typename, typename ...&gt; struct ptr_unwrap;

template &lt;typename Res, typename first, typename... tail&gt;
struct ptr_unwrap&lt;Res, first, tail...&gt; : ptr_unwrap&lt;apply_cv_t&lt;first, Res*&gt;, tail...&gt; {};

template &lt;typename Res&gt;
struct ptr_unwrap&lt;Res&gt; {using type = Res;};

/// --------------------------------------------------------------------------------------------------------------

template &lt;template&lt;typename, typename&gt; class, typename, typename, unsigned, typename = type_list&lt;&gt;, typename = void&gt;
struct modify_ptr_qualifier_impl;

template &lt;template&lt;typename, typename&gt; class Modifier, typename Mask, typename T, unsigned counter, typename... types&gt;
struct modify_ptr_qualifier_impl&lt;Modifier, Mask, T, counter, type_list&lt;types...&gt;,
                              std::enable_if_t&lt;std::is_pointer&lt;T&gt;::value &amp;&amp; counter != 0&gt;&gt; :
	modify_ptr_qualifier_impl&lt;Modifier, Mask, std::remove_pointer_t&lt;T&gt;, counter-1, type_list&lt;T, types...&gt;&gt;
{};

template &lt;template&lt;typename, typename&gt; class Modifier, typename Mask, typename T, unsigned counter, typename... types&gt;
struct modify_ptr_qualifier_impl&lt;Modifier, Mask, T, counter, type_list&lt;types...&gt;,
                              std::enable_if_t&lt;!std::is_pointer&lt;T&gt;::value || counter == 0&gt;&gt; :
	ptr_unwrap&lt;typename Modifier&lt;Mask, T&gt;::type, types...&gt;
{};
</code></pre>
<p><code>Mask</code> enthält dabei die zu verändernden qualifier. <code>Modifier</code> führt die Modifizierungen durch, <code>counter</code> zählt herunter.</p>
<p>Anschließend noch die Namen definieren:</p>
<pre><code>#include &lt;limits&gt;

#define DEFINE_APPLY_PQ(apply_name, templ, name, cv)                                                   \
	template &lt;typename T, unsigned counter = std::numeric_limits&lt;unsigned&gt;::max()&gt;                   \
	struct apply_name##_ptr_##name : modify_ptr_qualifier_impl&lt;templ##_##name, void cv, T, counter&gt; {}; \
                                                                                                       \
	template &lt;typename T, unsigned counter = std::numeric_limits&lt;unsigned&gt;::max()&gt;                   \
	using apply_name##_ptr_##name##_t = typename apply_name##_ptr_##name&lt;T, counter&gt;::type;

DEFINE_APPLY_PQ(remove, subtract, const, const)
DEFINE_APPLY_PQ(remove, subtract, volatile, volatile)
DEFINE_APPLY_PQ(remove, subtract, cv, const volatile)

DEFINE_APPLY_PQ(add, apply, const, const)
DEFINE_APPLY_PQ(add, apply, volatile, volatile)
DEFINE_APPLY_PQ(add, apply, cv, const volatile)
</code></pre>
<p>Und ein klitzekleines Testprogramm:</p>
<pre><code>template &lt;typename U, typename V&gt;
constexpr void assert_same()
{
	static_assert (std::is_same&lt;U, V&gt;::value, &quot;&quot;);
}

int main()
{
	assert_same&lt;add_ptr_const_t&lt;int volatile* volatile* const volatile, 1&gt;, int volatile* const volatile* const volatile&gt;();
	assert_same&lt;add_ptr_const_t&lt;int volatile* volatile* const volatile, 2&gt;, int const volatile* volatile* const volatile&gt;();
	assert_same&lt;add_ptr_cv_t   &lt;int**, 1&gt;, int* const volatile*&gt;();

	assert_same&lt;remove_ptr_const_t&lt;int volatile* const* const volatile, 1&gt;, int volatile** const volatile&gt;();
	assert_same&lt;remove_ptr_volatile_t&lt;int volatile* volatile* const volatile, 2&gt;, int* volatile* const volatile&gt;();
	assert_same&lt;remove_ptr_cv_t&lt;int* const volatile*, 1&gt;, int**&gt;();
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2409051</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2409051</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Thu, 17 Jul 2014 07:40:51 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Thu, 17 Jul 2014 10:56:35 GMT]]></title><description><![CDATA[<p>Arcoth schrieb:</p>
<blockquote>
<p>Zeiger sind aber stets spaßiger.</p>
</blockquote>
<p>Und wo würde ich das einsetzen?</p>
<pre><code>template &lt;typename T, typename U&gt; struct apply_const    : std::conditional&lt;std::is_const   &lt;T&gt;::value, U const   , U&gt; {};
</code></pre>
<p>das conditional kannst du dir auch sparen. Bringt mich aber auf eine spassige Implementation von identity:</p>
<pre><code class="language-cpp">template &lt;typename T&gt; struct identity : std::conditional&lt;true, T, void&gt; {};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2409074</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2409074</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Thu, 17 Jul 2014 10:56:35 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Thu, 17 Jul 2014 11:31:59 GMT]]></title><description><![CDATA[<blockquote>
<p>Und wo würde ich das einsetzen?</p>
</blockquote>
<p>Habe ich etwa versehentlich den Eindruck erweckt dass das irgendwo praktisch einsetzbar wäre? War nur zum Spaß. <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="🙂"
    /></p>
<blockquote>
<p>das conditional kannst du dir auch sparen</p>
</blockquote>
<p>Ja, indem ich selber partiell Spezialisiere. Das bedeutet nur mehr Schreibaufwand; Warum sollte ich auf die Type-Traits verzichten wollen?<br />
Oder hast du etwa einen cleveren Weg gefunden es zu schreiben (genauso lang aber ohne ein <code>conditional</code> -Artiges Template)?</p>
<blockquote>
<p>Bringt mich aber auf eine spassige Implementation von identity:</p>
</blockquote>
<p>Die habe ich doch schonmal gesehen! Wo bloß, vielleicht auf SO...? <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/2409080</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2409080</guid><dc:creator><![CDATA[Columbo]]></dc:creator><pubDate>Thu, 17 Jul 2014 11:31:59 GMT</pubDate></item><item><title><![CDATA[Reply to const einfach on Thu, 17 Jul 2014 11:41:05 GMT]]></title><description><![CDATA[<p>Arcoth schrieb:</p>
<blockquote>
<blockquote>
<p>das conditional kannst du dir auch sparen</p>
</blockquote>
<p>Ja, indem ich selber partiell Spezialisiere. Das bedeutet nur mehr Schreibaufwand; Warum sollte ich auf die Type-Traits verzichten wollen?<br />
Oder hast du etwa einen cleveren Weg gefunden es zu schreiben (genauso lang aber ohne ein <code>conditional</code> -Artiges Template)?</p>
</blockquote>
<p>ach ne, habe nicht richtig hingeschaut und missverstanden, was der Code tun soll..</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2409086</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2409086</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Thu, 17 Jul 2014 11:41:05 GMT</pubDate></item></channel></rss>