同名友元函数和方法
Friend function and method with the same name
以下 classes 定义声明了一个友元函数,为其提供内联定义。我试图从 class 方法中调用与友元函数同名的友元函数,但为了使其工作,我必须从封闭的命名空间访问它(这也需要前向声明,class C
下面)。为什么名称查找适用于 class A
而在 class B
中不起作用?注意B::swap
的参数和友元函数的参数不一样
#include <utility>
struct A {
A(int x) : v{ x } {}
friend void swap(A& x, A& y) { std::swap(x.v, y.v); }
void swapm(A& other) { swap(*this, other); }
private:
int v;
};
struct B {
B(int x) : v{ x } {}
friend void swap(B& x, B& y) { std::swap(x.v, y.v); }
void swap(B& other) { swap(*this, other); } // <-- This doesn't compile
private:
int v;
};
struct C;
void swap(C& x, C& y);
struct C {
C(int x) : v{ x } {}
friend void swap(C& x, C& y) { std::swap(x.v, y.v); }
void swap(C& other) { ::swap(*this, other); }
private:
int v;
};
int main()
{
A a1{ 1 }, a2{ 2 }; swap(a1, a2); a1.swapm(a2);
B b1{ 3 }, b2{ 4 }; swap(b1, b2); b1.swap(b2);
C c1{ 5 }, c2{ 6 }; swap(c1, c2); c1.swap(c2);
}
inline
friend
?为什么不 static
在这种情况下?而不是 friend
?然后创建一个全局的调用 static
。对我来说,这是一个糟糕的设计,而不是实际问题。
方法 swap
应该是完成工作的方法而不是 friend
(因为不再需要朋友了):
struct C {
C(int x) : v{ x } {}
void swap(C& other) { std::swap(this->v, other.v); }
private:
int v;
};
void swap(C& x, C& y)
{
x.swap(y);
}
不管这是个好主意,下面是对失败原因的解释:
编译器使用几个不同的处理阶段来确定您的程序所说的内容。 class B
没有编译的原因是因为发生的失败发生在 friend
被注意到之前。让我解释一下:
当编译器开始尝试弄清楚 swap
的含义时,它会进行名称查找。它使用特定的规则来指定应该查看的位置。这是简化的,但基本上它首先查找在本地范围内定义的符号,然后在 class 范围内,然后在封闭(命名空间等)范围内。它找到在 class 范围内定义的那个,然后停止查找。 swap
没有采用这 2 个参数,因此编译失败。
friend
声明允许自由函数访问 B
的内部结构,作为您在全局中声明的 swap
函数的附加声明命名空间。如果编译器在名称查找中考虑全局命名空间中的函数,编译器将考虑这些声明。在classB
中,编译器还没到这个阶段就已经停止处理了。 (并且 friend
声明在更晚的阶段是必要的,当编译器正在编译与 B
对象一起使用的 swap
函数版本时,并且想要弄清楚, "in this function called swap
that can take these 2 parameters; can I access B
's internals?")
在 class A
中,您使用了不同的名称。在找到您的免费 swap
函数之前,名称查找阶段不会成功。在 class C
中,您给出了名称查找特定说明,"hey, when you're looking up swap
, look in global-namespace scope, and ignore the ones in local- and class-scope that you might find."
(注意:名称查找的描述和 friend
在@PeteBecker 的评论后更新。)
以下 classes 定义声明了一个友元函数,为其提供内联定义。我试图从 class 方法中调用与友元函数同名的友元函数,但为了使其工作,我必须从封闭的命名空间访问它(这也需要前向声明,class C
下面)。为什么名称查找适用于 class A
而在 class B
中不起作用?注意B::swap
的参数和友元函数的参数不一样
#include <utility>
struct A {
A(int x) : v{ x } {}
friend void swap(A& x, A& y) { std::swap(x.v, y.v); }
void swapm(A& other) { swap(*this, other); }
private:
int v;
};
struct B {
B(int x) : v{ x } {}
friend void swap(B& x, B& y) { std::swap(x.v, y.v); }
void swap(B& other) { swap(*this, other); } // <-- This doesn't compile
private:
int v;
};
struct C;
void swap(C& x, C& y);
struct C {
C(int x) : v{ x } {}
friend void swap(C& x, C& y) { std::swap(x.v, y.v); }
void swap(C& other) { ::swap(*this, other); }
private:
int v;
};
int main()
{
A a1{ 1 }, a2{ 2 }; swap(a1, a2); a1.swapm(a2);
B b1{ 3 }, b2{ 4 }; swap(b1, b2); b1.swap(b2);
C c1{ 5 }, c2{ 6 }; swap(c1, c2); c1.swap(c2);
}
inline
friend
?为什么不 static
在这种情况下?而不是 friend
?然后创建一个全局的调用 static
。对我来说,这是一个糟糕的设计,而不是实际问题。
方法 swap
应该是完成工作的方法而不是 friend
(因为不再需要朋友了):
struct C {
C(int x) : v{ x } {}
void swap(C& other) { std::swap(this->v, other.v); }
private:
int v;
};
void swap(C& x, C& y)
{
x.swap(y);
}
不管这是个好主意,下面是对失败原因的解释:
编译器使用几个不同的处理阶段来确定您的程序所说的内容。 class B
没有编译的原因是因为发生的失败发生在 friend
被注意到之前。让我解释一下:
当编译器开始尝试弄清楚 swap
的含义时,它会进行名称查找。它使用特定的规则来指定应该查看的位置。这是简化的,但基本上它首先查找在本地范围内定义的符号,然后在 class 范围内,然后在封闭(命名空间等)范围内。它找到在 class 范围内定义的那个,然后停止查找。 swap
没有采用这 2 个参数,因此编译失败。
friend
声明允许自由函数访问 B
的内部结构,作为您在全局中声明的 swap
函数的附加声明命名空间。如果编译器在名称查找中考虑全局命名空间中的函数,编译器将考虑这些声明。在classB
中,编译器还没到这个阶段就已经停止处理了。 (并且 friend
声明在更晚的阶段是必要的,当编译器正在编译与 B
对象一起使用的 swap
函数版本时,并且想要弄清楚, "in this function called swap
that can take these 2 parameters; can I access B
's internals?")
在 class A
中,您使用了不同的名称。在找到您的免费 swap
函数之前,名称查找阶段不会成功。在 class C
中,您给出了名称查找特定说明,"hey, when you're looking up swap
, look in global-namespace scope, and ignore the ones in local- and class-scope that you might find."
(注意:名称查找的描述和 friend
在@PeteBecker 的评论后更新。)