公众朋友交换成员函数
在复制和交换成语的美丽答案有一段代码,我需要一点帮助:
class dumb_array { public: // ... friend void swap(dumb_array& first, dumb_array& second) // nothrow { using std::swap; swap(first.mSize, second.mSize); swap(first.mArray, second.mArray); } // ... }; 他又加了一张纸条
还有其他的说法,我们应该专门为我们的typesstd :: swap,提供一个在一个自由function交换,一个类交换,但这是不必要的:任何正确使用交换将通过一个非限定的调用,我们的function将通过ADLfind。 一个function就可以了。
 和friend我有点“不友好”的说法,我必须承认。 所以,我的主要问题是: 
- 看起来像一个免费的function ,但它的内部类体呢?
-   为什么不是这个swap静态 ? 它显然不使用任何成员variables。
-   “任何适当的交换使用将通过ADLfind交换” ?  ADL将search命名空间,对吗? 但是,它也看内部类? 或者在这里friend进来?
副题:
-  用C ++ 11,我应该用noexcept标记我的swap吗?
-  用C ++ 11和它的范围 ,我应该把friend iter begin()放在friend iter begin()和friend iter end()? 我觉得这里不需要friend,对吧?
 有几种写swap ,比其他的更好一些。 但是,随着时间的推移,发现一个单一的定义效果最好。 让我们考虑一下如何考虑编写一个swap函数。 
 我们首先看到像std::vector<>这样的容器有一个单参数成员函数swap ,比如: 
 struct vector { void swap(vector&) { /* swap members */ } }; 
 当然,我们class也应该,对吧? 那么,不是真的。 标准库有各种不必要的东西 ,而成员swap就是其中之一。 为什么? 我们继续。 
 我们应该做的是确定什么是经典的,以及我们的class级需要做什么来处理它。 而交换的规范方法是使用std::swap 。 这就是为什么成员函数没有用:它们不是我们应该如何交换的东西,一般来说,对std::swap的行为没有影响。 
 那么,为了使std::swap工作,我们应该提供(和std::vector<>应该提供) std::swap的专门化,对吧? 
 namespace std { template <> // important! specialization in std is OK, overloading is UB void swap(myclass&, myclass&) { // swap } } 
那么这肯定会在这种情况下工作,但它有一个明显的问题:function专业化不能是局部的。 也就是说,我们不能用这个专门化模板类,只有特定的实例:
 namespace std { template <typename T> void swap<T>(myclass<T>&, myclass<T>&) // error! no partial specialization { // swap } } 
这种方法在某些时候有效,但不是全部。 一定会有更好的办法。
 有! 我们可以使用friendfunction,并通过ADLfind它: 
 namespace xyz { struct myclass { friend void swap(myclass&, myclass&); }; } 
 当我们想交换一些东西的时候,我们把† std::swap关联起来,然后进行一个不合格的调用: 
 using std::swap; // allow use of std::swap... swap(x, y); // ...but select overloads, first // that is, if swap(x, y) finds a better match, via ADL, it // will use that instead; otherwise it falls back to std::swap 
 什么是friendfunction? 这个地区有混乱。 
 在C ++被标准化之前, friend函数做了一个叫做“朋友名注入”的东西,代码的行为就好像函数是否写在了周围的名字空间中一样。 例如,这些是等同的标准: 
 struct foo { friend void bar() { // baz } }; // turned into, pre-standard: struct foo { friend void bar(); }; void bar() { // baz } 
 但是,当ADL被发明时,这被删除。  friend函数只能通过ADLfind; 如果你想要它作为一个自由的function,它需要被声明如此(例如见这个 )。 但是! 有一个问题。 
 如果你只是使用std::swap(x, y) ,那么你的重载将永远不会被find,因为你已经明确地说过“在std查找,而在其他地方”! 这就是为什么有些人build议编写两个函数:一个是通过ADLfind的函数,另一个是处理明确的std:: qualifications。 
 但就像我们所看到的那样,这不可能在所有情况下都起作用,而且我们最终会变得丑陋。 相反,习惯交换是另外一条路线:不是将类作为提供std::swap ,而是std::swap者的工作,以确保它们不使用像上面那样的合格swap 。 而且,只要人们知道这一点,这个工作就会很顺利。 但问题在于:需要使用不合格的电话是不直观的。 
 为了方便起见,一些类似Boost的库提供了boost::swap函数,它只是一个非限定的swap调用, std::swap作为一个关联的名字空间。 这有助于使事情简洁一些,但它仍然是一个无赖。 
 请注意,C ++ 11对std::swap的行为没有任何改变,我和其他人错误地认为是这种情况。 如果你有点这个, 请阅读这里 。 
 总之:会员function只是噪音,专业化是丑陋的,不完整的,但friendfunction是完整的,有效的。 而当你交换,要么使用boost::swap或与std::swap关联的非限定swap 。 
  †非正式地,如果在函数调用期间将会考虑一个名字,则这个名字是相关联的 。 有关详细信息,请阅读第3.4.2节。 在这种情况下,通常不考虑std::swap ; 但是我们可以把它关联起来(把它添加到由不合格的swap考虑的重载集合中),从而可以find它。 
该代码相当于( 几乎在任何情况下):
 class dumb_array { public: // ... friend void swap(dumb_array& first, dumb_array& second); // ... }; inline void swap(dumb_array& first, dumb_array& second) // nothrow { using std::swap; swap(first.mSize, second.mSize); swap(first.mArray, second.mArray); } 
一个类中定义的朋友函数是:
- 放置在封闭的命名空间中
-  自动inline
- 能够在没有进一步资格的情况下引用该课程的静态成员
 确切的规则在[class.friend]部分(我引用C ++ 0x草案的第6和7段): 
函数可以定义在一个类的朋友声明中,当且仅当该类是一个非本地类(9.8),函数名是不合格的,函数具有命名空间范围。
这样的function隐式内联。 在一个类中定义的朋友函数在它定义的类的(词法)范围内。 在类外定义的朋友函数不是。