Как обеспечить функцию подкачки для моего класса?

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

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

2) Свободное положение swap в том же пространстве имен.

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

4) Все вышесказанное.

Спасибо.

EDIT: Похоже, я не ясно изложил свой вопрос. В принципе, у меня есть класс шаблона, и мне нужно STL algos использовать (эффективный) метод swap, который я написал для этого класса.

Ответы

Ответ 1

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) Вы имеете в виду явную специализацию. Частично все еще что-то еще, а также невозможно для функций, только structs/classes. Таким образом, поскольку вы не можете специализировать 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) выбрано, потому что оно лучше подходит.

Ответ 2

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

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

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

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

если вы хотите создать одну функцию для реализации всех трех свопов (не для того, чтобы этот примерный класс их оправдал), вы просто так же, как 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);
}

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

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