如何在c++中使用namespace::function选择函数的单个重载

How to select a single overload of a function with using namespace::function in C++?

本文关键字:选择 function 函数 重载 单个 namespace c++      更新时间:2023-10-16

考虑以下c++代码:

namespace A {
    void f() { // first function
    }
    void f(int) { // second function
    }
}
...
using A::f; // introduces both functions

有没有一种方法可以只引入一个函数?

该行为在标准中定义良好。

C++03 7.3.3 The using declaration:

"……如果名字是重载成员函数的名字,那么所有命名的函数都应该是可访问的

using关键字将把所有名称带入当前作用域。因此,在当前的代码中,这是不可能的。

但是,您可以将名称部分地引入文件,如下所示:

namespace A {
  void f();  // declaration
}
using A::f;
// now only `A::f()` is visible in the subsequent code
// technically `A::f(int)` is not yet visible (thus unusable)
// introduce the other function later on
namespace A {
  void f(int);
}

演示。

编辑:更好的方法是将A::f(int)放在嵌套的namesapce中,并引入别名(为了方便使用)。

namespace A {
  void f();
  namespace Internal {
    void f(int);
  }
}
using A::f;
namespace A_ = A::Internal;

现在,其他功能也可用A_::f(int)

据我所知没有。如果有问题,可以编写一个包装器函数。

void f(int i) { A::f(i); }

除了剩下的答案,我还会再举一些例子。

许多c++编程书籍通常通过在源文件开头添加以下行来公开整个STD名称空间:

using namespace std;
在现实生活中,暴露完整的名称空间实际上是一种不好的做法,因为在某些时候可能会发生各种冲突,特别是当代码由从事同一任务的许多开发人员提供时。这种编程风格也违背了面向对象编程的基本规则之一——通过封装数据,避免暴露超出实际需要的内容。这就是为什么类有public和private成员,getter和setter等等。名称空间只是对信息进行分组的另一种方式。暴露整个std命名空间是违反此规则的,特别是如果您只想使用std::coutstd::cinstd::endl。您可以使用轻松地将应用于特定的函数,这允许您进行更精确的控制,并更有可能避免在某些时候可能使用的多个名称空间中的命名冲突:
using std::cout;
using std::cin;
using std::endl;
这允许您在代码中调用coutcinendl而不使用名称空间前缀。如果您在某些时候遇到命名冲突,使用
-指令查看一组要容易得多,而不是想知道您暴露的错误来自整个命名空间的哪个地方。 如果有一个命名空间链或者命名空间的名字太长,人们也会对单个函数/变量使用using指令。如果你有
namespace my_really_long_and_pointless_namespace_that_does_nothing_at_all {
    void foo() { ... }
}

namespace1 {
    namespace2 {
        ...
            namepaceN {
                void foo() { ... }
            }
    }
}

每次要调用foo()方法时都必须编写完整的代码,这是非常痛苦的。通过编写

using my_really_long_and_pointless_namespace_that_does_nothing_at_all::foo;
分别为

using namespace1::namespace2:: ... ::namespaceN::foo;

试着这样做:

namespace A { 
    void f() { // first function 
    } }
using A::f; // introduces only above function
namespace A { 
    void f(int) { // second function 
    } 
} 

可以将它们包装在另一个作用域中:

namespace B { // Wrap the first function
    void f() { A::f(); }
}
namespace C { // Wrap the second function
    void f(int i) { A::f(i); }
}
int main(int argc, char *argv[])
{
    {
        using B::f; // Make the first function available
        f();
    } // Make the first function unavailable
    {
        using C::f; // Make the second function available
        f(0);
    } // Make the second function unavailable
    return 0;
}

但是我不认为你可以用一个单独的using声明。

c++没有机制可以从命名空间中导入一个特定的函数重载。

作为一种变通方法,你可以将一个函数调用包装成一个局部函数:

static inline void f(int i) { A::f(i); }

关键字static非常重要-

  1. 降低当前编译单元的全局命名空间污染的风险
  2. 可以在多个编译单元中执行此操作(因此可以放在头文件中)
  3. 它允许编译器省略额外的函数调用(调用f()A::f()在生成的代码中没有区别)
  4. 如果从未调用f,则不会生成额外的代码