Как обеспечить функцию подкачки для моего класса? - PullRequest
80 голосов
/ 17 июня 2011

Как правильно включить мои swap в алгоритмах STL?

1) Член swap.Использует ли std::swap трюк SFINAE для использования члена swap.

2) Отдельно стоящее swap в том же пространстве имен.

3) Частичная специализация std::swap.

4) Все вышеперечисленное.

Спасибо.

РЕДАКТИРОВАТЬ: Похоже, я не сформулировал свой вопрос четко.По сути, у меня есть шаблонный класс, и мне нужны алгоритмы STL для использования (эффективного) метода подкачки, который я написал для этого класса.

Ответы [ 2 ]

90 голосов
/ 17 июня 2011

1) является правильным использованием из swap. Пишите это таким образом, когда вы пишете код «библиотеки» и хотите включить ADL (поиск, зависящий от аргументов) на swap. Кроме того, это не имеет ничего общего с SFINAE.

// some algorithm in your code
template<class T>
void foo(T& lhs, T& rhs){
  using std::swap; // enable 'std::swap' to be found
                   // if no other 'swap' is found through ADL
  // some code ...
  swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
                  // or falls back on 'std::swap'
  // more code ...
}

2) Это правильный способ предоставить функцию swap для вашего класса.

namespace Foo{

class Bar{}; // dummy

void swap(Bar& lhs, Bar& rhs){
  // ...
}

}

Если сейчас используется swap, как показано в 1), ваша функция будет найдена. Кроме того, вы можете сделать эту функцию другом, если вам абсолютно необходимо, или предоставить члена swap, который вызывается бесплатной функцией:

// version 1
class Bar{
public:
  friend void swap(Bar& lhs, Bar& rhs){
    // ....
  }
};

// version 2
class Bar{
public:
  void swap(Bar& other){
    // ...
  }
};

void swap(Bar& lhs, Bar& rhs){
  lhs.swap(rhs);
}

3) Вы имеете в виду явную специализацию. Частичное - это еще что-то и не возможно для функций, только структуры / классы. Таким образом, поскольку вы не можете специализировать std::swap для шаблонных классов, у вас есть для предоставления бесплатной функции в вашем пространстве имен. Неплохо, если можно так сказать. Теперь также возможна явная специализация, но обычно вы не хотите специализировать шаблон функции :

namespace std
{  // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs){
  // ...
}

}

4) Нет, поскольку 1) отличается от 2) и 3). Кроме того, наличие 2) и 3) всегда приводит к выбору 2), потому что он подходит лучше.

1 голос
/ 15 декабря 2016

Чтобы ответить на EDIT, где классы могут быть шаблонными классами, вам вообще не нужна специализация. рассмотрим такой класс:

template <class T>
struct vec3
{
    T x,y,z;
};

Вы можете определить классы, такие как:

vec3<float> a;
vec3<double> b;
vec3<int> c;

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

template <class T>
void swap(vec3<T> &a, vec3<T> &b)
{
    using std::swap;
    swap(a.x,b.x);
    swap(a.y,b.y);
    swap(a.z,b.z);
}

Функция шаблона подкачки должна находиться в том же пространстве имен, что и класс, который вы пытаетесь поменять. следующий метод найдет и использует этот своп, даже если вы не ссылаетесь на это пространство имен с помощью ADL:

using std::swap;
swap(a,b);
...