簡體   English   中英

std ::用G ++交換怪異

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM