Перегрузка глобальной подкачки для пользовательского типа

Стандарт C++ запрещает объявление типов или определение чего-либо в пространстве имен std, но это действительно позволяет Вам специализировать стандартные шаблоны STL для пользовательских типов.

Обычно, когда я хочу специализироваться std::swap для моего собственного шаблонного типа я просто делаю:

namespace std
{
  template <class T>
  void swap(MyType<T>& t1, MyType<T>& t2)
  {
     t1.swap(t2);
  }
}

... и это удается прекрасный. Но я не совсем уверен, ли моя обычная практика стандартная совместимый. Я делаю это правильно?

12
задан Channel72 8 February 2010 в 16:51
поделиться

6 ответов

То, что у вас есть, это не специализация, это перегрузка и именно то, что запрещено стандартом. (Тем не менее, в настоящее время он почти всегда будет работать на практике, и может быть для вас приемлемым)

Вот как вы предоставляете свой собственный swap для вашего шаблона класса:

template<class T>
struct Ex {
  friend void swap(Ex& a, Ex& b) {
    using std::swap;
    swap(a.n, b.n);
  }
  T n;
}

И вот как вы вызываете swap, который, как вы заметите, используется и в Ex's swap:

void f() {
  using std::swap; // std::swap is the default or fallback
  Ex<int> a, b;
  swap(a, b); // invokes ADL
}

Связанный: Важность и необходимость специализации шаблона функции

15
ответ дан 2 December 2019 в 18:18
поделиться

Почему бы вам просто не определить подкачку в пространстве имен MyType и не использовать возможности поиска, зависящие от аргументов?

3
ответ дан 2 December 2019 в 18:18
поделиться

Из-за поиска, зависящего от аргументов (он же Koenig), я считаю, что вы можете указать свой собственный своп в пространстве имен того типа, для которого он нужен, и он будет предпочтительнее :: std :: swap . Кроме того, я считаю, что шаблон для :: std :: swap будет расширяться по-разному для классов, которые имеют свою собственную функцию-член подкачки, и поэтому вы можете добавить эту функцию-член в класс, и она будет использоваться для вашего типа .

3
ответ дан 2 December 2019 в 18:18
поделиться

Редактировать

См. Статью Скотта Мейера: см. Эффективное 3-е издание C ++ , пункт 25: подумайте о поддержке безбрасывающего свопа (p106-p112) для подтверждения моего ответа.

Оригинальный ответ

Скотт Мейерс писал об этом, поэтому мой ответ исходит из памяти.

Сначала определите функцию подкачки в пространстве имен вашего класса.Например:

namespace MyNamespace
{
   class MyClass { /* etc. */ } ;

   template<typename T>
   class MyTemplate { /* etc. */ } ;

   void swap(MyClass & lhs, MyClass & rhs)
   {
      // the swapping code (**)
   }

   template<typename T>
   void swap(MyTemplate<T> & lhs, MyTemplate<T> & rhs)
   {
      // the swapping code (**)
   }
}

Затем, , если возможно (это не всегда возможно для шаблонных классов (*)), укажите функцию подкачки в пространстве имен std. Например:

namespace std
{
   template<>
   void swap<MyNamespace::MyClass>(MyNamespace::MyClass & lhs, MyNamespace::MyClass & rhs)
   {
      // the swapping code (**)
   }

   // The similar code for MyTemplate is forbidden, so don't try
   // to uncomment it
   //
   // template<typename T>
   // void swap<MyNamespace::MyTemplate<T> >(MyNamespace::MyTemplate<T> & lhs, MyNamespace::MyTemplate<T> & rhs)
   // {
   //   // the swapping code (**)
   // }
}

При использовании функции подкачки сделайте это косвенно, импортируя функцию подкачки std в вашу область видимости. Например:

void doSomething(MyClass & lhs, MyClass & rhs)
{
   // etc.

   // I swap the two objects below:
   {
      using std::swap ;
      swap(lhs, rhs) ;
   }

   // etc.
}

void doSomethingElse(MyTemplate<int> & lhs, MyTemplate<int> & rhs)
{
   // etc.

   // I swap the two objects below:
   {
      using std::swap ;
      swap(lhs, rhs) ;
   }

   // etc.
}

Как только у меня появится доступ к своим книгам, я размещу здесь точную ссылку.

  • (*) шаблонная частичная специализация функции запрещена
  • (**) конечно, хорошим шаблоном является объявление в классе метода «подкачки», вызов функции подкачки методом подкачки и попросите пользователя вызвать функцию подкачки.
1
ответ дан 2 December 2019 в 18:18
поделиться

Определите свой тип и функцию подкачки в одном пространстве имен:

namespace foo
{
   struct Bar
   {
   };

   void swap(Bar & t1, Bar& t2)
   {
     // whatever
   }
}

int main()
{
    using std::swap;
    foo::Bar a, b;
    swap(a, b); // Argument-dependent lookup chooses foo::swap
                // if it exists, or else reverts to std::swap
}
-1
ответ дан 2 December 2019 в 18:18
поделиться

Определить собственный своп . Эта функция должна вызывать std :: swap для любого типа T, кроме ваших типов.

namespace help // my namespace
{ 

  template <class T> 
  void swap(T& t1, T& t2) 
  { 
     ::std::swap(t1, t2);  // Redirect to std for almost all cases
  } 

  // My special case: overloading
  template <class T> 
  void swap(MyType<T>& t1, MyType<T>& t2) 
  { 
     t1.swap(t2); 
  } 

}  //  namespace help 

// Sample
int main() 
{

   MyType<int> t1, t2; // may be add initialization
   int i1=5, i2=7;

   help::swap(t1, t2); //  Your swap
   help::swap(i1, i2); //  Redirect to std::swap
}
-1
ответ дан 2 December 2019 в 18:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: