【问题标题】:How to select a single overload of a function with using namespace::function in C++?如何在 C++ 中使用 namespace::function 选择函数的单个重载?
【发布时间】:2011-10-27 21:04:23
【问题描述】:

考虑以下 C++ 代码。

namespace A {
    void f() { // first function
    }

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

有没有办法只引入一个函数?

【问题讨论】:

  • using 始终适用于标识符,而不适用于以它们命名的特定实体。就是这样。

标签: c++ namespaces using


【解决方案1】:

C++ 没有从命名空间导入特定函数重载的机制。

作为一种解决方法,您可以将函数调用包装到本地函数中:

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

关键字static很重要-

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

【讨论】:

    【解决方案2】:

    除了其他答案,我还会再举一些例子。

    许多 C++ 编程书籍经常通过在源文件开头的某处添加以下行来公开整个 STD 命名空间:

    using namespace std;
    

    在现实生活中公开完整的命名空间实际上碰巧是一种不好的做法,因为在某些时候可能会发生各种冲突,尤其是当许多开发人员从事同一任务时提供代码时。这种编程风格也违反了面向对象编程的基本规则之一——通过封装数据来避免暴露超出实际需要的内容。这就是为什么类有公共和私有成员、getter 和 setter 等的原因。命名空间只是对信息进行分组的另一种方式。暴露整个 std 命名空间是违反这条规则的,特别是如果你只想使用 std::coutstd::cinstd::endl。您可以轻松地将 using 应用到特定函数,这使您可以更精确地控制,并更有可能避免您可能在某些时候使用的多个命名空间中的命名冲突:

    using std::cout;
    using std::cin;
    using std::endl;
    

    这允许您在代码中调用 coutcinendl,而无需命名空间前缀。如果您在某个时候遇到命名冲突,那么查看一组 using 指令会容易得多,而不是想知道您暴露的错误来自整个命名空间的哪个位置。

    如果存在命名空间链或命名空间的名称太长,人们也会对单个函数/变量使用 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;
    

    让你的手指省点工夫。

    【讨论】:

      【解决方案3】:

      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);
      }
      

      Demo.

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

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

      现在,其他功能也可以作为A_::f(int)使用。

      【讨论】:

      • 你的演示有缺陷——你在声明之前调用了A::f(int),所以当然没有找到。这是一个固定版本:ideone.com/2weTx
      • @iammilind:虽然第二种方法是正确的方法,第一种方法是不正确的,采用这种方法将是代码维护的噩梦。编写简单明了的代码总是更好,下一个接触它的人很容易理解,这样的hackery不符合要求。
      【解决方案4】:

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

      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 声明来做到这一点。

      【讨论】:

        【解决方案5】:

        标准中明确定义了该行为。

        C++03 7.3.3 The using declaration:

        “...如果名称是重载成员函数的名称,则所有命名的函数都应可访问。”。

        【讨论】:

          【解决方案6】:

          尝试这样做:

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

          【讨论】:

            【解决方案7】:

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

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

            【讨论】:

              猜你喜欢
              • 2010-09-27
              • 1970-01-01
              • 1970-01-01
              • 2019-03-30
              • 2023-03-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多