这是一个奇怪的地方,我不知道,如果它是C标准,我的编译器(G版本4.6.3在Ubuntu 12.04,这是最新的长期支持版本的Ubuntu)或与我,谁不明白;-)
@H_301_27@解决方法
该代码简单如下:
#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); // 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); // 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模式运行,我认为是这样,您不能在模板中使用本地定义的类型.如果是这种情况,您可以在命名空间级别定义类型,使其工作,否则可以在C11模式下进行编译.[*]
如果您想知道为什么第二种情况可行,该标准不提供专业化
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添加了任何新的成员变量,那么它们将不被替换. 所有这一切,就像旁注:你不应该从标准容器继承,因为它们从来没有被设计为继承. [*]免责声明:我不知道在特定版本的编译器中是否支持此功能,您将不得不仔细检查.