在struct / class声明中使用using指令?

时间:2010-12-06 03:03:43

标签: c++ language-features using-directives

我发现我的C ++ 头文件使用所有完全限定类型(与4个嵌套命名空间一样深)非常难以阅读(并且输入非常繁琐)。这是一个问题(所有的答案都提供了实现它的混乱的替代方案,但是问题): 是否有强烈的理由反对在结构和类中引入范围的using-directive用C ++语言 (虽然允许在函数中使用作用域声明)?

e.g。

class Foo : public Bar
{
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;
    using Bar::MemberFunc; // no conflict with this

    // e.g. of how messy my header files are without scoped using-directive
    void FooBar(System::Network::Win32::Sockets::Handle handle, System::Network::Win32::Sockets::Error& error /*, more fully-qualified param declarations... */);
};

由于namespace是一个关键字,我认为它足够明显,不会与使用Bar::MemberFunc等范围的声明产生冲突。

编辑:仔细阅读问题--->我加粗了。提醒:我们讨论如何提高示例的可读性。建议如何在C ++语言中实现scoped using-directive(即通过添加关键字/构造等) NOT 答案(如果你能找到一种优雅的方法来使用现有的C ++实现它)语言标准,那么它当然是一个答案)!

5 个答案:

答案 0 :(得分:11)

有时我这样做可以达到几乎相同的效果:

namespace detail {
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;

    class Foo : public Bar
    {
         void FooBar(Handle handle, Error& error);
    };
}
using detail::Foo;

答案 1 :(得分:9)

鉴于类范围内的using声明未被继承,这可能有效。该名称仅在该类声明中有效,或在嵌套类的声明内有效。但我认为这有点超载一个类的概念,其概念应该更大。

在Java和Python中,个别文件以特殊方式处理。您可以使用import声明将其他命名空间中的名称注入到文件中。这些名称(嗯,不完全是Python,但在这里解释得太复杂)只能在该文件中可见。

对我来说,这种能力不是与阶级宣言联系在一起,而是考虑到自己的范围。如果它有意义,甚至在函数定义中,这将允许注入的名称在几个类声明中使用。

这是一个我更喜欢的想法,因为它允许这些东西,同时仍然使用声明为您提供类级别的好处:

using {
   // A 'using' block is a sort of way to fence names in.  The only names
   // that escape the confines of a using block are names that are not
   // aliases for other things, not even for things that don't have names
   // of their own.  These are things like the declarations for new
   // classes, enums, structs, global functions or global variables.
   // New, non-alias names will be treated as if they were declared in
   // the scope in which the 'using' block appeared.

   using namespace ::std;
   using ::mynamespace::mytype_t;
   namespace mn = ::mynamespace;
   using ::mynamespace::myfunc;

   class AClass {
     public:
      AClass(const string &st, mytype_t me) : st_(st), me_(me) {
         myfunc(&me_);
      }

     private:
      const string st_;
      mn::mytype_t me_;
   };
// The effects of all typedefs, using declarations, and namespace
// aliases that were introduced at the level of this block go away
// here.  typedefs and using declarations inside of nested classes
// or namespace declarations do not go away.
} // end using.

// Legal because AClass is treated as having been declared in this
// scope.
AClass a("Fred", ::mynamespace::mytype_t(5));

// Not legal, alias mn no longer exists.
AClass b("Fred", mn::mytype_t);

// Not legal, the unqualified name myfunc no longer exists.
AClass c("Fred", myfunc(::mynamespace::mytype_t(5));

这类似于在函数中声明局部变量的块。但在这种情况下,您声明的范围非常有限,您将更改名称查找规则。

答案 2 :(得分:0)

也许名称空间别名?

namespace MyScope = System::Network::Win32::Sockets;

答案 3 :(得分:0)

您可以在类声明中使用typedef来实现相同的

class Foo : public Bar
{
      typedef System::Network::Win32::Sockets::Handle Handle;
      typedef System::Network::Win32::Sockets::Error Error;

      void FooBar(Handle handle, Error& error);
};

答案 4 :(得分:-2)

名称空间的明显好处是它们允许您避免命名冲突。但是,通过将整个命名空间引入类声明中,这种好处是无效的。 System命名空间中的函数完全可能与您自己的Bar :: MemberFunc函数冲突。当您添加注释“与此不冲突”时,您甚至会在示例代码中注明这一点。

您显然不希望将完整的命名空间引入您的类中:

using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;

并且你不能使用像这样的语句添加更窄的范围到类声明中。将这些直接放入类声明中是非法的。

using System::Network::Win32::Sockets::Handle;
using System::Network::Win32::Sockets::Error;

可以做的是使用未命名的命名空间。所以,你的头文件看起来像这样:

namespace {
    using System::Network::Win32::Sockets::Handle;
    using System::Network::Win32::Sockets::Error;
}

class Foo : public Bar
{
    using Bar::MemberFunc;

    // clean!
    void FooBar(Handle handle, Error& error /*, more declarations*/);
};

这有三个明显的优点。

  1. 未引入整个命名空间的内容。这有助于更轻松地避免命名冲突。
  2. 在您的课程声明之前,您有一个列表,列出您的课程所依赖的正常工作。
  3. 您的功能声明是干净的。
  4. 如果我错了,请纠正我;我只是简单地测试了一下。快速写了一个例子,然后编译。