[英]Overloading the QDataStream << and >> operators for a user-defined type
[英]Overloading global swap for user-defined type
C ++標准禁止在命名空間std
聲明類型或定義任何內容,但它允許您為用戶定義的類型專門化標准STL模板。
通常,當我想將std::swap
專門用於我自己的自定義模板類型時,我只是這樣做:
namespace std
{
template <class T>
void swap(MyType<T>& t1, MyType<T>& t2)
{
t1.swap(t2);
}
}
......這很好。 但我不完全確定我的慣常做法是否符合標准。 我這樣做了嗎?
你所擁有的不是專業化,它是超載,正是標准禁止的。 (但是,它幾乎總是在實踐中起作用,並且可能是您可以接受的。)
以下是為類模板提供自己的交換的方法:
template<class T>
struct Ex {
friend void swap(Ex& a, Ex& b) {
using std::swap;
swap(a.n, b.n);
}
T n;
}
以下是你如何調用swap,你會注意到它也用於Ex的交換:
void f() {
using std::swap; // std::swap is the default or fallback
Ex<int> a, b;
swap(a, b); // invokes ADL
}
相關: 功能模板專業化的重要性和必要性
為什么不在MyType的命名空間中定義swap並利用依賴於參數的查找功能?
由於參數依賴(aka Koenig)查找,我相信你可以在你想要它的類型的命名空間中指定你自己的交換,它將優先於::std::swap
。 此外,我相信::std::swap
的模板將針對具有自己的交換成員函數的類進行不同的擴展,因此您可以將該成員函數添加到類中,並將用於您的類型。
for a confirmation of my answer. 請參閱Scott Meyer的文章:參見以確認我的答案。
Scott Meyers寫了這個,所以我的答案來自記憶。
首先,在類的命名空間中定義交換函數。 例如 :
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 (**)
}
}
(it is not always possible for templated classes (*) ), specialize the swap function in the namespace std. 然后, (模板化類(*)並不總是可能),請在命名空間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 std
內重載(17.6.4.2.1§1)
如果C ++程序向
namespace std
或namespace std
中的命名namespace std
添加聲明或定義,則它是未定義的,除非另有說明。 只有當聲明取決於用戶定義的類型並且特化符合原始模板的標准庫要求且未明確禁止時,程序才可以將任何標准庫模板的模板特化添加到namespace std
。
因此,更喜歡將您的模板類型放入您自己的命名空間,並在該命名空間中定義非成員swap()
(這不是絕對必要的,但是很好的做法)。 這樣,如果x
或y
在您的命名空間中,則swap(x,y)
將通過參數依賴查找(ADL,即Koenig查找)從任何地方工作。
namespace my_ns {
template <typename T> class MyType
{
public:
void swap( MyType & other ) noexcept;
};
template <typename T>
void swap( MyType<T> & lhs, MyType<T> & rhs ) noexcept
{
lhs.swap(rhs);
}
} // namespace my_ns
使用swap()
代碼通常應該使用using namespace std
技術。 這樣,您的交換版本將由ADL找到,它將優先於std::swap()
函數,因為它更專業。
// client code
MyType<Bla> x, y;
/* ... some code ... */
using namespace std;
swap( x, y ); // will call your swap version
在同一名稱空間中定義您的類型和交換函數:
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
}
定義自己的swap
。 除了你的類型,這個函數必須為任何類型T調用std :: swap。
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
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.