<?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[Generische Implementierung eines Tagged Pointers]]></title><description><![CDATA[<p>Hallo Forengemeinde,</p>
<p>Ich habe mir zu Übungszwecken einen generischen tagged_ptr implementiert. Ich würde gerne wissen, inwieweit sich das mit dem Standard verträgt. Zumindest funktionieren tut es bei mir.</p>
<p>Hier der Code:</p>
<pre><code class="language-cpp">template &lt;unsigned N&gt;
using unsigned_ = std::integral_constant&lt;unsigned, N&gt;;

template &lt;unsigned N&gt;
using intptr_t_ = std::integral_constant&lt;std::intptr_t, N&gt;;

template &lt;unsigned A, unsigned B&gt;
struct pow
	: unsigned_&lt;A * pow&lt;A, B - 1&gt;::value&gt;
{};

template &lt;unsigned A&gt;
struct pow&lt;A, 0&gt;
	: unsigned_&lt;1&gt;
{};

template &lt;unsigned N&gt;
struct make_bitmask
	: intptr_t_&lt;1 &lt;&lt; N - 1 | make_bitmask&lt;N - 1&gt;::value&gt;
{};

template &lt;&gt;
struct make_bitmask&lt;0&gt;
	: intptr_t_&lt;0&gt;
{};

template &lt;typename T, unsigned Bits&gt;
struct tagged_ptr
{
	static_assert(alignof(T) &gt;= pow&lt;2, Bits&gt;::value, &quot;pointers to this type cannot be tagged with this number of bits&quot;);

	struct bit_reference
	{
		bit_reference(std::intptr_t&amp; p, std::size_t i) : p(p), i(i) {}

		bit_reference&amp; operator = (bool b)
		{
			p = (p &amp; ~(1 &lt;&lt; i)) | (b &lt;&lt; i);
			return *this;
		}

		operator bool() const { return p &amp; (1 &lt;&lt; i); }

	private:
		std::intptr_t&amp; p;
		std::size_t const i;
	};

	struct const_bit_reference
	{
		const_bit_reference(std::intptr_t const&amp; p, std::size_t i) : p(p), i(i) {}

		operator bool() const { return p &amp; (1 &lt;&lt; i); }

	private:
		std::intptr_t const&amp; p;
		std::size_t const i;
	};

	tagged_ptr() : ptr(nullptr) {}
	tagged_ptr(T* ptr) : ptr(ptr) {}

	template &lt;typename U&gt;
	tagged_ptr(tagged_ptr&lt;U, Bits&gt; const&amp; u)
		: ptr(&amp;*u)
	{}

	      bit_reference operator [] (std::size_t i)       { return       bit_reference(int_value(), i); }
	const_bit_reference operator [] (std::size_t i) const { return const_bit_reference(int_value(), i); }

	T&amp; operator *  () const { return *ptr_value(); }
	T* operator -&gt; () const { return  ptr_value(); }

private:
	static std::intptr_t const bitmask = make_bitmask&lt;Bits&gt;::value;

	tagged_ptr const&amp; const_this() const { return *this; }

	std::intptr_t&amp; int_value()
	{
		return const_cast&lt;std::intptr_t&amp;&gt;(const_this().int_value());
	}

	std::intptr_t const&amp; int_value() const
	{
		return reinterpret_cast&lt;std::intptr_t const&amp;&gt;(ptr);
	}

	T* ptr_value() const
	{
		return reinterpret_cast&lt;T*&gt;(int_value() &amp; ~bitmask);
	}

	T* ptr;
};

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; static_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(static_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; const_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(const_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; reinterpret_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(reinterpret_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; dynamic_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(dynamic_cast&lt;OutType*&gt;(&amp;*in));
}
</code></pre>
<p>Ein kleines Testprogramm:</p>
<pre><code class="language-cpp">int main()
{
	int i = 42;

	tagged_ptr&lt;int, 2&gt; p1 = &amp;i;
	p1[0] = true;
	std::cout &lt;&lt; p1[0] &lt;&lt; '\n';
	std::cout &lt;&lt; *p1 &lt;&lt; '\n';

	tagged_ptr&lt;int const, 2&gt; const p2 = p1;
	std::cout &lt;&lt; p2[0] &lt;&lt; '\n';
	std::cout &lt;&lt; *p2 &lt;&lt; '\n';
}
</code></pre>
<p>Funktionieren tut's, aber ist das korrekt und überall definiertes Verhalten?</p>
<p>Grüße,<br />
Der Kellerautomat</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/304324/generische-implementierung-eines-tagged-pointers</link><generator>RSS for Node</generator><lastBuildDate>Mon, 10 Aug 2026 00:49:43 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/304324.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 03 Jun 2012 21:44:37 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Sun, 03 Jun 2012 21:44:37 GMT]]></title><description><![CDATA[<p>Hallo Forengemeinde,</p>
<p>Ich habe mir zu Übungszwecken einen generischen tagged_ptr implementiert. Ich würde gerne wissen, inwieweit sich das mit dem Standard verträgt. Zumindest funktionieren tut es bei mir.</p>
<p>Hier der Code:</p>
<pre><code class="language-cpp">template &lt;unsigned N&gt;
using unsigned_ = std::integral_constant&lt;unsigned, N&gt;;

template &lt;unsigned N&gt;
using intptr_t_ = std::integral_constant&lt;std::intptr_t, N&gt;;

template &lt;unsigned A, unsigned B&gt;
struct pow
	: unsigned_&lt;A * pow&lt;A, B - 1&gt;::value&gt;
{};

template &lt;unsigned A&gt;
struct pow&lt;A, 0&gt;
	: unsigned_&lt;1&gt;
{};

template &lt;unsigned N&gt;
struct make_bitmask
	: intptr_t_&lt;1 &lt;&lt; N - 1 | make_bitmask&lt;N - 1&gt;::value&gt;
{};

template &lt;&gt;
struct make_bitmask&lt;0&gt;
	: intptr_t_&lt;0&gt;
{};

template &lt;typename T, unsigned Bits&gt;
struct tagged_ptr
{
	static_assert(alignof(T) &gt;= pow&lt;2, Bits&gt;::value, &quot;pointers to this type cannot be tagged with this number of bits&quot;);

	struct bit_reference
	{
		bit_reference(std::intptr_t&amp; p, std::size_t i) : p(p), i(i) {}

		bit_reference&amp; operator = (bool b)
		{
			p = (p &amp; ~(1 &lt;&lt; i)) | (b &lt;&lt; i);
			return *this;
		}

		operator bool() const { return p &amp; (1 &lt;&lt; i); }

	private:
		std::intptr_t&amp; p;
		std::size_t const i;
	};

	struct const_bit_reference
	{
		const_bit_reference(std::intptr_t const&amp; p, std::size_t i) : p(p), i(i) {}

		operator bool() const { return p &amp; (1 &lt;&lt; i); }

	private:
		std::intptr_t const&amp; p;
		std::size_t const i;
	};

	tagged_ptr() : ptr(nullptr) {}
	tagged_ptr(T* ptr) : ptr(ptr) {}

	template &lt;typename U&gt;
	tagged_ptr(tagged_ptr&lt;U, Bits&gt; const&amp; u)
		: ptr(&amp;*u)
	{}

	      bit_reference operator [] (std::size_t i)       { return       bit_reference(int_value(), i); }
	const_bit_reference operator [] (std::size_t i) const { return const_bit_reference(int_value(), i); }

	T&amp; operator *  () const { return *ptr_value(); }
	T* operator -&gt; () const { return  ptr_value(); }

private:
	static std::intptr_t const bitmask = make_bitmask&lt;Bits&gt;::value;

	tagged_ptr const&amp; const_this() const { return *this; }

	std::intptr_t&amp; int_value()
	{
		return const_cast&lt;std::intptr_t&amp;&gt;(const_this().int_value());
	}

	std::intptr_t const&amp; int_value() const
	{
		return reinterpret_cast&lt;std::intptr_t const&amp;&gt;(ptr);
	}

	T* ptr_value() const
	{
		return reinterpret_cast&lt;T*&gt;(int_value() &amp; ~bitmask);
	}

	T* ptr;
};

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; static_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(static_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; const_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(const_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; reinterpret_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(reinterpret_cast&lt;OutType*&gt;(&amp;*in));
}

template &lt;typename OutType, typename InType, unsigned Bits&gt;
tagged_ptr&lt;OutType, Bits&gt; dynamic_tagged_ptr_cast(tagged_ptr&lt;InType, Bits&gt; in)
{
	return tagged_ptr&lt;OutType, Bits&gt;(dynamic_cast&lt;OutType*&gt;(&amp;*in));
}
</code></pre>
<p>Ein kleines Testprogramm:</p>
<pre><code class="language-cpp">int main()
{
	int i = 42;

	tagged_ptr&lt;int, 2&gt; p1 = &amp;i;
	p1[0] = true;
	std::cout &lt;&lt; p1[0] &lt;&lt; '\n';
	std::cout &lt;&lt; *p1 &lt;&lt; '\n';

	tagged_ptr&lt;int const, 2&gt; const p2 = p1;
	std::cout &lt;&lt; p2[0] &lt;&lt; '\n';
	std::cout &lt;&lt; *p2 &lt;&lt; '\n';
}
</code></pre>
<p>Funktionieren tut's, aber ist das korrekt und überall definiertes Verhalten?</p>
<p>Grüße,<br />
Der Kellerautomat</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219003</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219003</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Sun, 03 Jun 2012 21:44:37 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Sun, 03 Jun 2012 23:22:40 GMT]]></title><description><![CDATA[<p>MMn. ist das nicht standard-konform.<br />
Du castest da <code>T*&amp;</code> zu <code>intptr_t&amp;</code> und modifizierst dann Bits. Das ist denke ich UB.</p>
<p>Wenn überhaupt, dann müsste dein <code>tagged_ptr</code> einen <code>intptr_t</code> als Member haben.<br />
Die Tag-Bits kannst du dann in den <code>intptr_t</code> reinverodern, und dann vor der Rückkonvertierung zu <code>T*</code> wieder rausmaskieren.</p>
<pre><code class="language-cpp">T* ptr_value()
    {
        return reinterpret_cast&lt;T*&gt;(m_ptr_as_int &amp; ~bitmask);
    }
</code></pre>
<p>Wobei ich mir jetzt nicht 100% sicher bin, ob<br />
a) die Konvertierung T* &lt;-&gt; intptr_t überhaupt garantiert ist und<br />
b) dabei garantiert ist dass ein Alignment von 2 auch dazu führt dass das LSB des intptr_t immer 0 ist</p>
<p>Wenn diese zwei Punkte gegeben sind, dann sollte es OK sein.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219018</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219018</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Sun, 03 Jun 2012 23:22:40 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 07:59:25 GMT]]></title><description><![CDATA[<p>Ich dachte, std::intrptr_t ist doch gerade dazu da, um den Zeiger als int verwenden zu können?<br />
Und was würde sich ändern, wenn der Member nun ein intptr_t wäre? <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/2219066</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219066</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Mon, 04 Jun 2012 07:59:25 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 09:52:03 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Ich dachte, std::intrptr_t ist doch gerade dazu da, um den Zeiger als int verwenden zu können?</p>
</blockquote>
<p>Ja, aber nicht um Referenzen darauf wild hin- und heracsten zu können.</p>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Und was würde sich ändern, wenn der Member nun ein intptr_t wäre? <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>
</blockquote>
<p>Dass du ohne reinterpret_cast Referenzen darauf zurückgeben kannst. Die Umwandlung in den Pointer ist dann ja sowieso eine Kopie.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219117</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219117</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Mon, 04 Jun 2012 09:52:03 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 10:24:43 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>Ja, aber nicht um Referenzen darauf wild hin- und heracsten zu können.</p>
</blockquote>
<p>Das ist doch dasselbe, nur in Pink. Beispiel:</p>
<pre><code class="language-cpp">T* ptr = ...;
ptr = reinterpret_cast&lt;T*&gt;(reinterpret_cast&lt;intptr_t&gt;(ptr) + 42);
</code></pre>
<p>ist doch gleichwertig mit</p>
<pre><code class="language-cpp">T* ptr = ...;
reinterpret_cast&lt;intptr_t&amp;&gt;(ptr) += 42;
</code></pre>
<p>... oder etwa nicht?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219134</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219134</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Mon, 04 Jun 2012 10:24:43 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 11:06:51 GMT]]></title><description><![CDATA[<p>Davon redet ja auch keiner <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="🙄"
    /><br />
Nochmal lesen...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219156</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219156</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Mon, 04 Jun 2012 11:06:51 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 11:12:35 GMT]]></title><description><![CDATA[<p>Ich kann euch nicht folgen. Genau das passiert doch bei meinem tagged_ptr:</p>
<pre><code class="language-cpp">T* ptr = reinterpret_cast&lt;T*&gt; /* (1) */ (reinterpret_cast&lt;intptr_t&gt; /* (2) */ (... /* (3) */ ) + 42 /* (4) */);
</code></pre>
<p>(3) ist der Konstruktor. Ein Pointer wird übergeben und gespeichert.<br />
(4) ist das Rechnen, das geschieht mithilfe der bit_reference im operator[].<br />
(1) und (2) sind die dafür erforderlichen Casts.</p>
<p>Das entspricht genau dem Ablauf in meinem tagged_ptr, insofern sehe ich das Problem jetzt nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219157</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219157</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Mon, 04 Jun 2012 11:12:35 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 11:24:12 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>pumuckl schrieb:</p>
<blockquote>
<p>Ja, aber nicht um Referenzen darauf wild hin- und heracsten zu können.</p>
</blockquote>
<p>Das ist doch dasselbe, nur in Pink. Beispiel:</p>
<pre><code class="language-cpp">T* ptr = ...;
ptr = reinterpret_cast&lt;T*&gt;(reinterpret_cast&lt;intptr_t&gt;(ptr) + 42);
</code></pre>
<p>ist doch gleichwertig mit</p>
<pre><code class="language-cpp">T* ptr = ...;
reinterpret_cast&lt;intptr_t&amp;&gt;(ptr) += 42;
</code></pre>
<p>... oder etwa nicht?</p>
</blockquote>
<p>Nein. Im ersten Fall konvertierst du Werte, im zweiten Falle behandelst du ein Zeigerobjekt, als ob es ein intptr_t-Objekt wäre. Praktisch wird die häufig zu keinem anderen beobachteten resultat führen, insbesondere im Falle von reinterpret_cast besteht die Konvertierung i.d.R. darin, dass das Bitmuster (value representation) 1:1 in den Wert des anderen Typs übernommen wird (das wird nicht vom Standard ausdrücklich so verlangt, außer dass die Konvertierung &quot;nicht überraschen&quot; sollte). Unter Umständen wird allerdings ein konstanter Ausdruck 0 bzw. ein nullptr anders behandelt.<br />
Das ist also theoretisch ein Portabilitätsproblem, allerdings vermutlich selten ein praktisches.<br />
Gleichermaßen würde es mich sehr überraschen, falls tatsächlich eine Implementation existiert, in der in korrekt ausgerichteten Zeigern die niederwertigen Bits nicht 0 sind. Schließlich ist Alignment von vornherein eine Einschränktung die aufgrund der Gegebenheiten konkreter Hardware existiert, und nicht, weil es für die Sprache oder darin geschriebener Programme irgendwie von direktem Nutzen wäre.</p>
<p>Viel wichtiger ist hier allerdings 3.10/10, d.h. die Regel, dass der in einem Objekt gespeicherte Wert - mit ein paar dort aufgezählten Ausnahmen - immer nur mit einem Ausruck des gleichen Typs ausgelesen werden darf. Hier geht es nicht um Portabilität sondern um Optimierung. Konsequenterweise wird dein Code solange funktionieren, wie du hinschaust, und dir erst dann um die Ohren fliegen, wenn du nicht mehr damit rechnest, das etwas schiefgehen kann.</p>
<p>hustbaer hat hier schon das richtige Vorgehen beschrieben.</p>
<p>Nur um es nochmal deutlich zu sagen: die zweite Variante führt hier zwangsläufig zu undefiniertem Verhalten.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219161</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219161</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 04 Jun 2012 11:24:12 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 11:26:10 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Ich kann euch nicht folgen. Genau das passiert doch bei meinem tagged_ptr:</p>
<pre><code class="language-cpp">T* ptr = reinterpret_cast&lt;T*&gt; /* (1) */ (reinterpret_cast&lt;intptr_t&gt; /* (2) */ (... /* (3) */ ) + 42 /* (4) */);
</code></pre>
<p>(3) ist der Konstruktor. Ein Pointer wird übergeben und gespeichert.<br />
(4) ist das Rechnen, das geschieht mithilfe der bit_reference im operator[].<br />
(1) und (2) sind die dafür erforderlichen Casts.</p>
<p>Das entspricht genau dem Ablauf in meinem tagged_ptr, insofern sehe ich das Problem jetzt nicht.</p>
</blockquote>
<pre><code class="language-cpp">p = (p &amp; ~(1 &lt;&lt; i)) | (b &lt;&lt; i);
</code></pre>
<p>p ist ein intptr_t&amp;, das tatsächlich auf ein T*-Objekt (in dem auch ein T*-Wert gespeichert wurde) verweist. Also führt der hier notwendige Lesezugrif zu UB.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219163</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219163</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 04 Jun 2012 11:26:10 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 14:21:59 GMT]]></title><description><![CDATA[<p>Alles klar, danke für die Erklärung. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f44d.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--thumbs_up"
      title=":+1:"
      alt="👍"
    /></p>
<p>Somit ist es also okay, wenn der tagged_ptr intern einen intptr_t hält? Ist das Verhalten dann zumindest implementation-defined oder undefined?<br />
Und wie verträgt sich das mit dem Byte-Order, den hustbär ja schon angesprochen hat? Evtl ein Little/Big-Endian-Switch erforderlich?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219256</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219256</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Mon, 04 Jun 2012 14:21:59 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 15:36:32 GMT]]></title><description><![CDATA[<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Somit ist es also okay, wenn der tagged_ptr intern einen intptr_t hält?</p>
</blockquote>
<p>ja</p>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Ist das Verhalten dann zumindest implementation-defined oder undefined?</p>
</blockquote>
<p>Abgesehen davon, dass die verwendeten Bits frei sein müssen, was der Standard nicht verlangt (man könnte das als conditionally-supported ansehen), gibt es keine Probleme.</p>
<p>Kellerautomat schrieb:</p>
<blockquote>
<p>Und wie verträgt sich das mit dem Byte-Order, den hustbär ja schon angesprochen hat? Evtl ein Little/Big-Endian-Switch erforderlich?</p>
</blockquote>
<p>Irrelevant, gerade weil Werte direkt konvertiert werden, bist du nicht von einer bestimmten Repräsentation abhängig.<br />
Lesenswert auch 3.7.4.3.</p>
<p>Könnte am Ende ungefähr so aussehen</p>
<pre><code class="language-cpp">private:
    template &lt;typename T, typename U&gt;
    static constexpr T implicit_cast(U v) { return v; }

public:
    tagged_ptr() : ptr(0) {}
    tagged_ptr(T* ptr) : data(reinterpret_cast&lt;std::uintptr_t&gt;(ptr)) {}

    template &lt;typename U&gt;
    tagged_ptr(tagged_ptr&lt;U, Bits&gt; const&amp; u)
        : data(reinterpret_cast&lt;std::uintptr_t&gt;(implicit_cast&lt;T*&gt;(u.get())) | u.get_tag())
    {}

    std::uintptr_t get_tag() const { return data &amp; ( ( 1u &lt;&lt; Bits ) - 1u ); }
    T* get() const { return reinterpret_cast&lt;T*&gt;( data ^ get_tag()); }

    bit_reference operator [] (std::size_t i) { return       bit_reference(data, i); }
    const_bit operator [] (std::size_t i) const { return const_bit(get_tag() &amp; ( 1u &lt;&lt; i ); }

    T&amp; operator *  () const { return *get(); }
    T* operator -&gt; () const { return  get(); }

private:
    std::uintptr_t data;
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2219303</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219303</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 04 Jun 2012 15:36:32 GMT</pubDate></item><item><title><![CDATA[Reply to Generische Implementierung eines Tagged Pointers on Mon, 04 Jun 2012 16:51:18 GMT]]></title><description><![CDATA[<p>Vielen Dank für die Hilfe <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f44d.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--thumbs_up"
      title=":+1:"
      alt="👍"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2219328</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2219328</guid><dc:creator><![CDATA[Kellerautomat]]></dc:creator><pubDate>Mon, 04 Jun 2012 16:51:18 GMT</pubDate></item></channel></rss>