<?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[Funktion abhängig der Größe eines Templateparameters überladen]]></title><description><![CDATA[<p>Hoi! <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>
<p>Ich habe eine Template-Funktion, die Objekte entgegennimmt</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
void foo(T const&amp; bar) 
...
</code></pre>
<p>Jedenfalls möchte ich, wenn sizeof(void*) &gt;= sizeof(T), das ganze per Value übergeben.</p>
<p>Ich weiß, eine warscheinlich unsinnige Mikrooptimierung, aber in meinem neuen Projekt geht es mir gerade um solche Sachen.</p>
<p>Weiß jemand Rat?<br />
Grüße,<br />
Flo</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/284997/funktion-abhängig-der-größe-eines-templateparameters-überladen</link><generator>RSS for Node</generator><lastBuildDate>Fri, 21 Aug 2026 17:58:31 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/284997.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 12 Apr 2011 15:28:09 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 15:28:09 GMT]]></title><description><![CDATA[<p>Hoi! <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>
<p>Ich habe eine Template-Funktion, die Objekte entgegennimmt</p>
<pre><code class="language-cpp">template&lt;typename T&gt;
void foo(T const&amp; bar) 
...
</code></pre>
<p>Jedenfalls möchte ich, wenn sizeof(void*) &gt;= sizeof(T), das ganze per Value übergeben.</p>
<p>Ich weiß, eine warscheinlich unsinnige Mikrooptimierung, aber in meinem neuen Projekt geht es mir gerade um solche Sachen.</p>
<p>Weiß jemand Rat?<br />
Grüße,<br />
Flo</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048151</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048151</guid><dc:creator><![CDATA[Ethon]]></dc:creator><pubDate>Tue, 12 Apr 2011 15:28:09 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 15:51:47 GMT]]></title><description><![CDATA[<p>Direkt für Funktionen nur mit Gefrickel und C++0x-Features, aber für Funktionsobjekte durch partielle Spezialisierung ganz einfach:</p>
<pre><code class="language-cpp">template&lt;typename T, bool by_reference=(sizeof(T) &gt; sizeof(void*))&gt; struct Foo
{
  Foo(const T&amp;)
  {
    std::cout&lt;&lt;&quot;Referenz\n&quot;;
  }
};

template&lt;&gt; template&lt;typename T&gt; struct Foo&lt;T, false&gt;
{
  Foo(T)
  {
    std::cout&lt;&lt;&quot;Value\n&quot;;
  }
};

int main()
{
  Foo&lt;int&gt;(2);
  Foo&lt;long double&gt;(2.);
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2048161</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048161</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Tue, 12 Apr 2011 15:51:47 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 17:43:12 GMT]]></title><description><![CDATA[<p>Hier noch zwei C++98-Lösungen. Im Prinzip kannst du mit Type-Traits was Kleines basteln:</p>
<pre><code class="language-cpp">template &lt;typename T, bool ByValue&gt;
struct ParameterImpl
{
	typedef T Type;
};

template &lt;typename T&gt;
struct ParameterImpl&lt;T, false&gt;
{
	typedef const T&amp; Type;
};

template &lt;typename T&gt;
struct Parameter : ParameterImpl&lt;T, (sizeof(T)&lt;=sizeof(void*))&gt;
{
};
</code></pre>
<p>Das Problem ist hier nur, dass bei der folgenden Funktion das Template-Argument nicht mehr automatisch hergeleitet werden kann, daher müsste man es beim Aufruf hinschreiben. Aber die Metafunktion kann sonst ab und zu praktisch sein.</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
void Foo(typename Parameter&lt;T&gt;::Type t);
</code></pre>
<p>Eine andere Lösung kommt ohne Angabe des Template-Arguments und mit SFINAE aus. Der zusätzliche Aufruf sollte eigentlich wegoptimiert werden. Du kannst auch andere Typen als <code>void</code> zurückgeben, dafür ist der zweite Template-Parameter von <code>enable_if</code> konzipiert.</p>
<pre><code class="language-cpp">template &lt;typename X&gt;
void FooImpl(X x);

template &lt;typename T&gt;
typename enable_if&lt;( sizeof(T)&lt;=sizeof(void*) )&gt;::type Foo(T t)
{
	FooImpl&lt;T&gt;(t);
}

template &lt;typename T&gt;
typename enable_if&lt;( sizeof(T)&gt;sizeof(void*) )&gt;::type Foo(const T&amp; t)
{
	FooImpl&lt;const T&amp;&gt;(t);
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2048254</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048254</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Tue, 12 Apr 2011 17:43:12 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 20:27:31 GMT]]></title><description><![CDATA[<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/26744">@Ethon</a>: Dir ist hoffentlich klar, daß die Größe eines Objekts nicht der einzige Grund ist, zwischen der Übergabe als Referenz und der Übergabe als Kopie zu wählen. Es gibt genug Klassen, die (aus Sicht des sizeof()) klein sind, aber trotzdem nicht als Kopie übergeben werden können oder sollten sollten, z.B.:<br />
- nicht-kopierbare Objekte (z.B. boost::scoped_ptr - da verhindert das Klassendesign, daß sie kopiert werden)<br />
- Container (enthalten mitunter nur ein bis zwei Zeiger im &quot;Rumpf&quot;, aber der Kopierkonstruktor muß möglicherweise größere Datenmengen auf dem Heap kopieren)<br />
- Klassen mit destruktiver Kopiersemantik (z.B. std::auto_ptr)</p>
<p>Da würde ich im Zweifelsfall lieber ein paar Prozessortakte für die Dereferenzierung in Kauf nehmen als mir mit derartigen Problemen meine Programme zu zerstören.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048375</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048375</guid><dc:creator><![CDATA[CStoll]]></dc:creator><pubDate>Tue, 12 Apr 2011 20:27:31 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 20:45:43 GMT]]></title><description><![CDATA[<p>CStoll schrieb:</p>
<blockquote>
<p>Da würde ich im Zweifelsfall lieber ein paar Prozessortakte für die Dereferenzierung in Kauf nehmen als mir mit derartigen Problemen meine Programme zu zerstören.</p>
</blockquote>
<p>Also geht's nicht sinnvoll, die paar Takte zu sparen zu automatosieren. Schade. C++ ist dahingehend eine schlechte Spache. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f61e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--disappointed_face"
      title=":("
      alt="😞"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048385</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048385</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Tue, 12 Apr 2011 20:45:43 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 20:51:51 GMT]]></title><description><![CDATA[<p>Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat? Wenn ja, könnte man die obengenannten enable_if-Konstrukionen darauf ansetzen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048386</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048386</guid><dc:creator><![CDATA[CStoll]]></dc:creator><pubDate>Tue, 12 Apr 2011 20:51:51 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 20:57:06 GMT]]></title><description><![CDATA[<p>CStoll schrieb:</p>
<blockquote>
<p>Es gibt genug Klassen, die (aus Sicht des sizeof()) klein sind, aber trotzdem nicht als Kopie übergeben werden können oder sollten sollten</p>
</blockquote>
<p>Gute Einwände, CStoll.</p>
<p>Wenn man etwas defensiver vorgeht, kann man diese Probleme vermeiden. Beschränkt man sich auf skalare Typen, sind die meisten Fälle sind dann trotzdem noch abgedeckt. Mit der Metafunktion <code>is_scalar</code> aus Boost.TypeTraits (oder TR1/C++0x-Äquivalenten) kann diese Typeigenschaft geprüft werden. Das grösste Problem sehe ich hier bei Iteratoren, für diese müsste man allenfalls eine Spezialisierung einrichten. Vielleicht aber besser bei einem eigenen Template als direkt bei <code>is_scalar</code> .</p>
<p>Ist halt immer die Frage, wie weit man mit der Optimierung gehen will...</p>
<p>CStoll schrieb:</p>
<blockquote>
<p>Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat?</p>
</blockquote>
<p>Suchst du <code>has_trivial_copy</code> ? <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>
]]></description><link>https://www.c-plusplus.net/forum/post/2048390</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048390</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Tue, 12 Apr 2011 20:57:06 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:01:40 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>CStoll schrieb:</p>
<blockquote>
<p>Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat?</p>
</blockquote>
<p>Suchst du <code>has_trivial_copy</code> ? <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>Ja, ich glaube das war's. (wobei ich die Doku so deute, daß das eher pessimistisch bei der Aussage ist - aber für praktische Zwecke dürfte das reichen)</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048392</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048392</guid><dc:creator><![CDATA[CStoll]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:01:40 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:04:55 GMT]]></title><description><![CDATA[<p>CStoll schrieb:</p>
<blockquote>
<p>Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat? Wenn ja, könnte man die obengenannten enable_if-Konstrukionen darauf ansetzen.</p>
</blockquote>
<p>Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat. Ich denke, mit ihnen wäre einiges einfacher.<br />
Ups, wo wir schon dabei sind,<br />
- warum ist der Rückgabetyp eines Kunstuktors nicht void,<br />
- warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048393</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048393</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:04:55 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:25:42 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat.</p>
</blockquote>
<p>Ich kenne Smalltalk nicht, wie sehen die aus? Läuft das nicht auf was Ähnliches wie Template-Metaprogrammierung heraus, nur etwas benutzerfreundlicher?</p>
<p>volkard schrieb:</p>
<blockquote>
<p>warum ist der Rückgabetyp eines Kunstuktors nicht void</p>
</blockquote>
<p>Wahrscheinlich weil der Konstruktor nicht nichts zurückgibt. Schliesslich wird ein Konstruktor in einer Deklaration oder in einem Ausdruck aufgerufen, der das eben konstruierte Objekt zurückgibt. Der Typ eines solchen Ausdrucks ist im Gegensatz zu <code>void</code> -Funktionen nicht <code>void</code> .</p>
<p>volkard schrieb:</p>
<blockquote>
<p>- warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?</p>
</blockquote>
<p>Ich bin mir nicht sicher, könnte mir aber vorstellen, damit man sowas schreiben kann:</p>
<pre><code class="language-cpp">boolExpr ? DoSomething() : throw Exception()
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2048397</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048397</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:25:42 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:30:47 GMT]]></title><description><![CDATA[<p>Quatsch</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048399</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048399</guid><dc:creator><![CDATA[EOutOfResources]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:30:47 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:34:26 GMT]]></title><description><![CDATA[<p>Nexus schrieb:</p>
<blockquote>
<p>volkard schrieb:</p>
<blockquote>
<p>Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat.</p>
</blockquote>
<p>Ich kenne Smalltalk nicht, wie sehen die aus? Läuft das nicht auf was Ähnliches wie Template-Metaprogrammierung heraus, nur etwas benutzerfreundlicher?</p>
</blockquote>
<p>Nee. Ist die Magie über der Klasse als normale Klasse. Dadurch erst zugreifbar für Metaprogrammierung. In C++ ist es einfach nicht da.</p>
<p>Nexus schrieb:</p>
<blockquote>
<p>volkard schrieb:</p>
<blockquote>
<p>warum ist der Rückgabetyp eines Kunstuktors nicht void</p>
</blockquote>
<p>Wahrscheinlich weil der Konstruktor nicht nichts zurückgibt.</p>
</blockquote>
<p>Also falsch.</p>
<p>Nexus schrieb:</p>
<blockquote>
<p>volkard schrieb:</p>
<blockquote>
<p>- warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?</p>
</blockquote>
<p>Ich bin mir nicht sicher, könnte mir aber vorstellen, damit man sowas schreiben kann:</p>
<pre><code class="language-cpp">boolExpr ? DoSomething() : throw Exception()
</code></pre>
</blockquote>
<p>Wozu? Nur um im assert werfen zu können? Der Fehler war doch, daß assert ein Ausdruck war. Keinen hat's gejuckt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048401</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048401</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:34:26 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Tue, 12 Apr 2011 21:46:15 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>wo wir schon dabei sind,</p>
</blockquote>
<p>Wieso fordert <code>main</code> kein <code>return</code> ?<br />
EDIT: Oder wieso ist <code>argc</code> ein <code>int</code> un nicht ein <code>unsigned</code> ?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048403</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048403</guid><dc:creator><![CDATA[EOutOfResources]]></dc:creator><pubDate>Tue, 12 Apr 2011 21:46:15 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Wed, 13 Apr 2011 06:19:35 GMT]]></title><description><![CDATA[<p>volkard schrieb:</p>
<blockquote>
<p>warum ist der Rückgabetyp eines Kunstuktors nicht void</p>
</blockquote>
<p>Im Prinzip ist es irrelevant, welchen Rückgabewert der Konstruktor hat, weil es keine Möglichkeit gibt, ihn direkt aufzurufen.<br />
<code>MyClass a = MyClass(...)</code> ruft ihn nur indirekt auf, sonst müsste es <code>MyClass::MyClass(...)</code> heißen. Der Konstruktor ist aber auch nicht statisch, also ginge das auch nicht. Somit müsste man also danach <code>a.MyClass(...)</code> aufrufen können, das geht nicht.<br />
Da der Konstruktor somit niemals in einem Ausdruck verwendet werden kann, braucht er keinen Rückgabewert.</p>
<p>Interessanter wird die Sache beim Destruktor. Der kann in Ausdrücken verwendet werden. Laut <a href="http://ideone.com/gn36G" rel="nofollow">http://ideone.com/gn36G</a> scheint er beim GCC auch tatsächlich <code>void</code> als Rückgabewert zu haben, ob das der Standard genauso sieht, weiß ich aber nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048445</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048445</guid><dc:creator><![CDATA[ipsec]]></dc:creator><pubDate>Wed, 13 Apr 2011 06:19:35 GMT</pubDate></item><item><title><![CDATA[Reply to Funktion abhängig der Größe eines Templateparameters überladen on Wed, 13 Apr 2011 06:48:10 GMT]]></title><description><![CDATA[<p>ipsec schrieb:</p>
<blockquote>
<p>volkard schrieb:</p>
<blockquote>
<p>warum ist der Rückgabetyp eines Kunstuktors nicht void</p>
</blockquote>
<p>Im Prinzip ist es irrelevant, welchen Rückgabewert der Konstruktor hat, weil es keine Möglichkeit gibt, ihn direkt aufzurufen.</p>
</blockquote>
<p>Schade. Wäre direkter, als der Umweg per placement new.</p>
<p>ipsec schrieb:</p>
<blockquote>
<p><code>MyClass a = MyClass(...)</code> ruft ihn nur indirekt auf, sonst müsste es <code>MyClass::MyClass(...)</code> heißen. Der Konstruktor ist aber auch nicht statisch, also ginge das auch nicht. Somit müsste man also danach <code>a.MyClass(...)</code> aufrufen können, das geht nicht.</p>
</blockquote>
<p>Eine Aufrufabkürzung darf es ja geben. Warum ist er nicht statisch?</p>
<pre><code class="language-cpp">MyClass* p=malloc(sizeof(MyClass));
MyClass::constructor(p);
</code></pre>
<p>sieht doch hübsch aus. Man könnte zum Beispiel auf natürliche Weise die Adresse der Funktion ziehen.</p>
<blockquote>
<p>Da der Konstruktor somit niemals in einem Ausdruck verwendet werden kann, braucht er keinen Rückgabewert.</p>
</blockquote>
<p>void als Rückgabewert würde aber auch nicht schaden, sondern den Laden ein wenig vereinfachen. Third-Party-Tools hätten es leichter, den Konstruktor als Funktion zu erkennen. Und schau Dir folgenden seltsamen Code an:</p>
<pre><code class="language-cpp">void test(){
    //tuwas
    //if(was)
        return throw 0;//Klappt, seit der so spät nachträglichen Sprachvereinfachung, daß man void returnen darf. 
    //tuwasanderes
}

class MyClass{
    MyClass(){
    //tuwas
    //if(was)
        return throw 0;//error: returning a value from a constructor
    //tuwasanderes
    }
};
</code></pre>
<p>Da stimmt doch konzeptionell was nicht. Und es ist kein hübscher Weg, durch immer mehr Ausnahmeregeln die Ausnahmen zu regeln und dabei noch mehr Ausnahmen zu provozieren.</p>
<blockquote>
<p>Interessanter wird die Sache beim Destruktor. Der kann in Ausdrücken verwendet werden.</p>
</blockquote>
<p>Ja, der ist auch (fast) eine ganz normale Methode. Nur wenige Sonderregeln, wie daß er Basisklassendestruktoren automatisch aufruft, den vptr ändert, implementiert werden muß selbst wenn pur virtuell seiend, und nicht überladen werden kann. Kann man wenigstens seine Adresse ziehen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2048452</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2048452</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Wed, 13 Apr 2011 06:48:10 GMT</pubDate></item></channel></rss>