这是相应的问题,我想知道的是,是否有可能通过成员函数将全局函数引入重载决策?
我试过两种方式,但都不起作用:
void foo(double val) { cout << "double\n";}
class obj {
public:
using ::foo; // (1) compile error: using-declaration for non-member at class scope
void callFoo() {
using ::foo; // (2?will cause the global version always be called
foo(6.4);
foo(0);
}
private:
void foo(int val) {cout << "class member foo\n"; }
};
Run Code Online (Sandbox Code Playgroud)
我怀疑您能否让编译器根据类型调用一个或另一个。您当然可以使用本地包装函数,如下所示:
void callFoo() {
foo(6.4);
foo(0);
}
private:
void foo(double val) { ::foo(val); }
Run Code Online (Sandbox Code Playgroud)
包装器函数应该很好地内联成空,因此在优化编译时没有实际开销。
或者不要将成员和全局函数称为同名,这会让生活变得更轻松!
这是普通的旧的非限定名称查找,在 \xc2\xa73.4.1 [basic.lookup.unqual] 中指定:
\n\n\n\n\n1 在 3.4.1 列出的所有情况下,将按照每个相应类别中列出的顺序在范围中搜索声明;一旦找到名称的声明,名称查找就会结束。如果未找到\n 声明,则程序格式错误。
\n\n8 对于类的成员
\n\nX
,在成员函数体、默认参数、异常规范、 非静态数据成员的大括号或等于初始化器中使用的名称 (9.2 ),或者在 X 定义之外的类成员定义中,\n 位于 member\xe2\x80\x99s declarator-id之后之后,应通过\n 以下方式之一进行声明:\n
\n- 在使用它的块或封闭块(6.3)中使用之前,或
\n- 应是 (10.2) 类的成员
\nX
或基类的成员X
,或- 如果
\nX
是类Y
(9.7) 的嵌套类,则应是 的成员Y
,或者应是 的基类的成员Y
(此查找依次适用于Y
\xe2\x80\x99s 封闭类,从最里面的\ n 封闭类),或者- if
\nX
是本地类 (9.8) 或者是本地类的嵌套类,位于X
包含 class 定义的块中的 class 定义\n之前X
,或者- if
\nX
是 命名空间 的成员N
,或者是 的成员的类的嵌套类N
,或者是本地类或\n函数的本地类中的嵌套类,而该函数是 的成员N
,在使用之前\n命名空间中N
或 \xe2\x80\x99s 封闭命名空间之一中的名称N
。
首先请注意,一旦找到声明,名称查找就会停止。因此,如果您有using ::foo;
in callFoo()
,则查找foo
将在那里结束,并且永远不会触及第二个要点;如果没有,查找将在第二个项目符号点foo
找到该成员,而不会在其他地方搜索。foo()
指定非限定名称查找的方式意味着您将找到类成员或非类成员,但绝不会两者都找到。
\xc2\xa713.1.1.1 [over.call.func]/p3 中也注意到了这一点:
\n\n\n\n\n在非限定函数调用中,名称不由 -> 或 .\n 运算符限定,并且具有更通用的primary-expression形式。按照函数调用中名称查找的正常规则 (3.4) 在函数调用的上下文中查找名称。该查找找到的函数声明构成了候选函数集。由于名称查找的规则,候选函数集由 (1) 完全非成员函数或 (2) 完全由某个类的成员函数组成
\nT
。在情况 (1) 中,参数列表\n 与调用中的表达式列表相同。在情况 (2) 中,参数列表是调用中的表达式列表,通过在限定函数调用中添加隐含对象参数来扩充。
类范围内的using声明必须命名基类成员 (\xc2\xa77.3.3 [namespace.udecl]/p3):
\n\n\n\n在用作成员声明的using 声明中,嵌套 名称说明符应命名所定义的类的基类。
\n