[英]std::swap weirdness with G++
這是一個奇怪的,我不知道,如果它是C ++標准,我的編譯器(Ubuntu 12.04上的G ++版本4.6.3,這是Ubuntu的最新長期支持版本)或我,誰不明白;-)
有問題的代碼簡單如下:
#include <algorithm> // for std::swap
void f(void)
{
class MyClass { };
MyClass aa, bb;
std::swap(aa, bb); // doesn't compile
}
嘗試使用G ++編譯時,編譯器會產生以下錯誤消息:
test.cpp: In function ‘void f()’:
test.cpp:6:21: error: no matching function for call to ‘swap(f()::MyClass&, f()::MyClass&)’
test.cpp:6:21: note: candidates are:
/usr/include/c++/4.6/bits/move.h:122:5: note: template<class _Tp> void std::swap(_Tp&, _Tp&)
/usr/include/c++/4.6/bits/move.h:136:5: note: template<class _Tp, long unsigned int _Nm> void std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm])
令人驚訝的結果是,只是將類定義移出函數使得代碼編譯正常:
#include <algorithm> // for std::swap
class MyClass { };
void f(void)
{
MyClass aa, bb;
std::swap(aa, bb); // compiles fine!
}
那么,std :: swap()不應該在類上工作,這些類是函數私有的嗎? 或者這是G ++的一個錯誤,也許是我正在使用的G ++的特定版本?
更令人費解的是,盡管MyListClass也是私有的(但是擴展了一個“官方”類,其中可能存在swap()的特定實現),以下內容確實再次起作用:
#include <algorithm> // for std::swap
#include <list> // for std::list
void g(void)
{
class MyListClass : public std::list<int> { };
MyListClass aa, bb;
std::swap(aa, bb); // compiles fine!
}
但只是從對象更改為指針,再次編譯失敗:
#include <algorithm> // for std::swap
#include <list> // for std::list
void g(void)
{
class MyListClass : public std::list<int> { };
MyListClass aa, bb;
MyListClass* aap = &aa;
MyListClass* bbp = &bb;
std::swap(aap, bbp); // doesn't compile!
}
當然,在我的實際應用中,類更復雜; 我盡可能地簡化代碼以仍然重現問題。
如果您在C ++ 03模式下運行(我認為是這種情況),則不允許在模板中使用本地定義的類型。 如果是這種情況,您可以在命名空間級別定義類型以使其工作,否則您可以在C ++ 11模式下編譯它應該編譯。[*]
如果你想知道為什么第二種情況有效,標准不提供專業化
template <typename T> void swap(T&,T&) // [1]
因為std::list
本身就是一個模板,你不能部分專門化模板功能。 它提供的是一個不同的基本模板:
template <typename T, typename A> void swap(list<T,A>&,list<T,A>&); // [2]
現在和前面的情況一樣,編譯器不能將本地類型與[1]一起使用,因此會被丟棄。 然后它嘗試[2],它發現它可以將本地類型的左值轉換為對基本std::list<int>
引用,之后轉換[2]是一個很好的候選者。 然后它會打電話
std::swap(static_cast<std::list<int&>>(aa),static_cast<std::list<int&>>(bb));
它不使用本地類型,而是使用命名空間級別std::list<int>
。
另一方面,它編譯的事實並不意味着它做你想要的。 特別是,如果擴展類型MyListClass
添加了任何新的成員變量,那么這些變量將不會被交換。
所有這些,只是作為旁注:你不應該繼承標准容器,因為它們從來沒有被設計為繼承。
[*]免責聲明:我不知道在特定版本的編譯器中是否支持此功能,您必須仔細檢查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.