公共朋友交换成员函数

| 在对复制和交换惯用语的漂亮回答中,有一段代码需要一些帮助:
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);
    }
    // ...
};
然后他加了一张纸条   还有其他主张,我们应该针对我们的类型专门使用std :: swap,在提供免费交换功能的同时提供类内交换,等等。但这都是不必要的:对交换的任何正确使用都将通过不合格的调用,我们的功能将通过ADL找到。一种功能将起作用。 我必须承认,对于“ 1”,我对“不友好”的说法有些不满。因此,我的主要问题是: 看起来像一个自由函数,但是它在类体内? 为什么
swap
不是静态的?它显然不使用任何成员变量。 \“任何正确使用交换的方法都可以通过ADL找出交换” \“? ADL将搜索名称空间,对吗?但是它也可以在类内部查看吗?还是这里出现
friend
? 附带问题: 使用C ++ 11,我应该用ѭ5标记我的
swap
吗? 使用C ++ 11及其range-for,我应该在类中以相同的方式放置
friend iter begin()
friend iter end()
吗?我认为这里不需要
friend
,对吗?     
已邀请:
swap
的写法有几种,有些比其他的要好。但是,随着时间的流逝,发现单个定义最有效。让我们考虑一下如何考虑编写writing2ѭ函数。 我们首先看到像
std::vector<>
这样的容器具有一个单参数成员函数
swap
,例如:
struct vector
{
    void swap(vector&) { /* swap members */ }
};
那么,我们的班级自然也应该吧?好吧,不是真的。标准库包含各种不必要的东西,成员
swap
是其中之一。为什么?我们继续。 我们应该做的是确定什么是规范的,以及班级需要做什么才能使用它。交换的标准方法是
std::swap
。这就是为什么成员函数没用的原因:它们通常不是我们应该如何交换事物的方式,并且与
std::swap
的行为无关。 那么,为了使
std::swap
工作,我们应该提供and15ѭ的专业知识(对
std::vector<>
应该提供),对吗?
namespace std
{
    template <> // important! specialization in std is OK, overloading is UB
    void swap(myclass&, myclass&)
    {
        // swap
    }
}
在这种情况下,这当然可以工作,但是存在一个明显的问题:功能专长不能是部分的。也就是说,我们不能仅使用特定的实例来专门化模板类:
namespace std
{
    template <typename T>
    void swap<T>(myclass<T>&, myclass<T>&) // error! no partial specialization
    {
        // swap
    }
}
此方法在某些时间有效,但并非所有时间都有效。肯定有更好的办法。 有!我们可以使用
friend
函数,并通过ADL找到它:
namespace xyz
{
    struct myclass
    {
        friend void swap(myclass&, myclass&);
    };
}
当我们想交换东西时,我们关联†15,然后进行不合格的通话:
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
什么是“ 1”功能?这个区域周围有混乱。 在C ++标准化之前,“ 1”函数进行了一些称为“朋友名称注入”的操作,其中代码的行为就好像该函数是在周围的命名空间中编写的。例如,这些是等效的预标准:
struct foo
{
    friend void bar()
    {
        // baz
    }
};

// turned into, pre-standard:    

struct foo
{
    friend void bar();
};

void bar()
{
    // baz
}
但是,当发明了ADL时,将其删除。然后只能通过ADL找到
friend
函数。如果您希望将其作为自由函数,则需要这样声明它(例如,参见此内容)。但是!出现问题了。 如果仅使用
std::swap(x, y)
,就永远不会发现您的过载,因为您已经明确地说“请看
std
,而没有其他地方”!这就是为什么有人建议编写两个函数的原因:一个是通过ADL找到的函数,另一个是处理显式的“ 32”资格的函数。 但是就像我们看到的那样,这并非在所有情况下都有效,并且最终导致丑陋的混乱。取而代之的是,惯用的交换走了另一条路:不是让类提供job15的工作,而是让交换者确保他们不使用合格的ѭ2的工作,就像上面一样。只要人们知道这一点,它就可以很好地工作。但是这里存在问题:需要使用不合格的呼叫是不直观的! 为了简化操作,像Boost这样的某些库提供了函数
boost::swap
,该函数只对just2ѭ进行了无限定的调用,并以
std::swap
作为关联的命名空间。这有助于使事情再次变得简洁,但仍然令人沮丧。 请注意,C ++ 11中的
std::swap
行为没有变化,我和其他人错误地认为是这种情况。如果您对此有所了解,请在此处阅读。 简而言之:成员函数仅仅是噪声,专业化是丑陋且不完整的,而
friend
函数却是完整且有效的。交换时,请使用
boost::swap
或不合格的
swap
并关联
std::swap
。 †非正式地,如果在函数调用期间要考虑名称,则将其关联。有关详细信息,请参阅第3.4.2节。在这种情况下,通常不考虑ѭ15。但是我们可以将其关联(将其添加到不合格的
swap
考虑的重载集合中),以便找到它。     
该代码等效于(几乎在所有方面):
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
无需进一步资格即可提及班级的静态成员 确切的规则在第ѭ47节中(我引用了C ++ 0x草案的第6和第7段):   当且仅当该类是非本地类(9.8),函数名称不合格且该函数具有名称空间范围时,才可以在该类的朋友声明中定义一个函数。      此类函数是隐式内联的。在类中定义的朋友功能在其定义的类的(词法)范围内。在类外部定义的朋友函数不是。     

要回复问题请先登录注册