Frage

Betrachten Sie die folgende Funktionsvorlage:

template<typename T> void Foo(T)
{
  // ...
}

Pass-by-value-Semantik Sinn machen, wenn T geschieht ein integraler Typ sein, oder zumindest eine Art, dass die billig zu kopieren. Mit Pass-by [const] -Referenz Semantik, auf der anderen Seite, macht mehr Sinn, wenn T eine teuere Art sein geschieht zu kopieren.

Lassen Sie uns für eine zweite davon ausgehen, dass Sie eine Bibliothek schreiben. Idealerweise als Bibliothek Implementierer, Ihre Aufgabe ist es Ihre Kunden mit einem sauberen API zur Verfügung zu stellen, die sowohl als generische und effizient wie möglich ist. Wie dann, bieten Sie eine generische Schnittstelle dass Caters auf beiden Arten von Argumente übergeben Strategien?


Hier ist mein erster Versuch, diese Arbeit zu bekommen:

#include <boost/type_traits.hpp>

template<typename T> struct DefaultCondition
{
  enum {value = boost::is_integral<T>::value /* && <other trait(s)> */};
};

template< typename T, class Condition = DefaultCondition<T> > class Select
{
  template<bool PassByValue = Condition::value, class Dummy = void> struct Resolve
  {
    typedef T type;
  };

  template<class Dummy> struct Resolve<false, Dummy>
  {
    typedef const T& type;
  };

  public: typedef typename Resolve<>::type type;
};

Typische Anwendungen:

template<typename T> class EnterpriseyObject
{
  typedef typename Select<T>::type type;

  public: explicit EnterpriseyObject(type)
  {
    // ...
  }
};

struct CustomType {};

void Usage()
{
  EnterpriseyObject<int>(0); // Pass-by-value.
  (EnterpriseyObject<CustomType>(CustomType())); // Pass-by-const-reference.
}

Das ist natürlich indirekt bricht impliziten Vorlage Argument Abzug für Nicht-Klassen-Templates:

template<typename T> void Foo(typename Select<T>::type)
{
  // ...
}

void Usage()
{
  Foo(0);      // Incomplete.
  Foo<int>(0); // Fine.
}

Das kann "feste" mit der Boost.Typeof Bibliothek und einem Makro, a la die WinAPI:

#define Foo(Arg) ::Foo<BOOST_TYPEOF((Arg))>((Arg))

Das ist zwar nur ein quasi-portable Hack.

Wie Sie sehen, mein allgemeiner Ansatz ist für alle Fälle nicht wirklich zufriedenstellend.


Als Bastler Programmierer, weder ich praktische Erfahrungen noch habe ich Zugang zu serienreifem Code als Referenz. Mir ist auch klar, dass dies wie ein schlechter Fall der vorzeitigen Optimierung scheinen mag, aber ich bin wirklich in ein paar Dinge interessiert:

  1. Haben Sie, oder haben Sie verwendet diese Art der Optimierung * in der Vergangenheit?
  2. Ist die Boost (oder jede andere öffentliche) Bibliothek bieten bereits ähnliche Funktionalität?
  3. Wenn die Antwort auf # 1 oder # 2 ist ein ‚Ja‘ - wie ist der Nicht-Klassen-Template Fall behandelt
  4. Gibt es offensichtliche Gefahren, dass ich nicht mit so etwas wie dies zu sehen bin?
  5. Schließlich ist dies auch eine vernünftige Sache zu tun?

* Nicht profiliert. ;)

War es hilfreich?

Lösung

  1. Ja. Die ganze Zeit. Ich benutze es selbst.
  2. Ja, verwenden Sie Boost.Utility Call Traits :)

    Verwendung wäre ...

    template <typename T>
    void foo(boost::call_traits<T>::param_type param)
    {
        // Use param
    }
    
  3. Soweit ich weiß, ist nicht-Klassen-Templates bestanden-by-Wert, wenn es schneller nicht ist. Dank Teil Template-Spezialisierung kann es relativ leicht angepasst werden.

  4. Sorry, las nicht wirklich, was du getan hast, es sieht genauso aus wie genau das, was ich vor durch ein paar Monate vergingen. Daher kann nicht wirklich diese Frage beantworten. Meine Empfehlung ist, nur durch Boost.Utility zu lesen.

  5. Natürlich!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top