Стандарт C++ запрещает объявление типов или определение чего-либо в пространстве имен std
, но это действительно позволяет Вам специализировать стандартные шаблоны STL для пользовательских типов.
Обычно, когда я хочу специализироваться std::swap
для моего собственного шаблонного типа я просто делаю:
namespace std
{
template <class T>
void swap(MyType<T>& t1, MyType<T>& t2)
{
t1.swap(t2);
}
}
... и это удается прекрасный. Но я не совсем уверен, ли моя обычная практика стандартная совместимый. Я делаю это правильно?
То, что у вас есть, это не специализация, это перегрузка и именно то, что запрещено стандартом. (Тем не менее, в настоящее время он почти всегда будет работать на практике, и может быть для вас приемлемым)
Вот как вы предоставляете свой собственный 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
}
Связанный: Важность и необходимость специализации шаблона функции
Почему бы вам просто не определить подкачку в пространстве имен MyType и не использовать возможности поиска, зависящие от аргументов?
Из-за поиска, зависящего от аргументов (он же Koenig), я считаю, что вы можете указать свой собственный своп в пространстве имен того типа, для которого он нужен, и он будет предпочтительнее :: std :: swap
. Кроме того, я считаю, что шаблон для :: std :: swap
будет расширяться по-разному для классов, которые имеют свою собственную функцию-член подкачки, и поэтому вы можете добавить эту функцию-член в класс, и она будет использоваться для вашего типа .
См. Статью Скотта Мейера: см. Эффективное 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.
}
Как только у меня появится доступ к своим книгам, я размещу здесь точную ссылку.
Определите свой тип и функцию подкачки в одном пространстве имен:
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
}
Определить собственный своп
. Эта функция должна вызывать 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
}