我发现我的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 ++实现它)语言标准,那么它当然是一个答案)!
答案 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*/);
};
这有三个明显的优点。
如果我错了,请纠正我;我只是简单地测试了一下。快速写了一个例子,然后编译。