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

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

1) Член swap, Есть ли std::swap использовать трюк SFINAE, чтобы использовать член swap,

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

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

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

Спасибо.

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

2 ответа

Решение

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), потому что он подходит лучше.

Кажется, что (2)swapв том же пространстве имен, где объявлен определенный пользователем класс) - единственный допустимый способ swap для пользовательского класса, потому что добавление объявлений в пространство имен std как правило, неопределенное поведение. Расширение пространства имен std (cppreference.com):

Это неопределенное поведение для добавления объявлений или определений в пространство имен std или в любое пространство имен, вложенное в stdс несколькими исключениями, отмеченными ниже

А также swap не обозначается как одно из тех исключений. Так что добавив свой swap перегрузка на std Пространство имен - это неопределенное поведение.

Также сказано, что стандартная библиотека использует неквалифицированный вызов swap функция для вызова пользовательского swap для пользовательского класса, если такой пользовательский swap предоставлен.

Swappable (cppreference.com):

Многие стандартные библиотечные функции (например, многие алгоритмы) ожидают, что их аргументы удовлетворят Swappable, что означает, что каждый раз, когда стандартная библиотека выполняет своп, она использует эквивалент using std::swap; swap(t, u);,

своп (www.cplusplus.com):

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

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

my::object a, b;
std::swap(a, b); // calls std::swap, not my::swap

Поэтому рекомендуется вызывать swap функционировать в коде пользователя так же, как это делается в стандартной библиотеке:

my::object a, b;
using std::swap;
swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.

Чтобы ответить на 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);
}

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

using std::swap;
swap(a,b);
Другие вопросы по тегам