c – std ::与G交换奇怪

前端之家收集整理的这篇文章主要介绍了c – std ::与G交换奇怪前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这是一个奇怪的地方,我不知道,如果它是C标准,我的编译器(G版本4.6.3在Ubuntu 12.04,这是最新的长期支持版本的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);          // 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&gt ;. 另一方面,它编译的事实并不意味着它会执行你想要的.特别地,如果扩展类型MyListClass添加了任何新的成员变量,那么它们将不被替换. 所有这一切,就像旁注:你不应该从标准容器继承,因为它们从来没有被设计为继承. [*]免责声明:我不知道在特定版本的编译器中是否支持功能,您将不得不仔细检查.

猜你在找的C&C++相关文章