提问人:Zach Saw 提问时间:12/6/2010 最后编辑:taskinoorZach Saw 更新时间:5/7/2017 访问量:31786
struct/class 声明中的 scoped using 指令?[复制]
Scoped using-directive within a struct/class declaration? [duplicate]
问:
我发现我的 C++ 头文件很难阅读(而且键入起来非常乏味),所有完全限定的类型(深入到 4 个嵌套命名空间)。这就是问题所在(所有答案都给出了实现它的混乱替代方案,但这不是问题):是否有充分的理由反对在 C++ 语言的结构和类中引入作用域 using-directive(虽然允许在函数中使用作用域 using-declaration)?
例如:
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++ 语言中实现作用域 using-directive(即通过添加关键字/构造等)不是一个答案(如果你能找到一种优雅的方式来实现它使用现有的 C++ 语言标准,那么它当然是一个答案)!
答:
也许是命名空间别名?
namespace MyScope = System::Network::Win32::Sockets;
评论
有时我这样做是为了达到几乎相同的效果:
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;
评论
detail
::Foo
鉴于类作用域的声明不是继承的,这可能有效。该名称仅在该类声明中或嵌套类的声明中有效。但我认为这有点用一个应该更大的想法来超载一个类的概念。using
在 Java 和 Python 中,单个文件以特殊方式处理。可以使用将其他命名空间中的名称注入到文件中的声明。这些名称(好吧,不完全是 Python,但这里解释起来太复杂了)仅在该文件中可见。import
在我看来,这种能力不与类声明挂钩,而是被赋予自己的范围。这将允许在多个类声明中使用注入的名称,如果它有意义,甚至在函数定义中使用。
这是我更喜欢的一个想法,因为它允许这些事情,同时仍然使用声明为您提供类级别的好处:
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));
这类似于在函数中为局部变量声明一个块。但在本例中,您声明的范围非常有限,您将在其中更改名称查找规则。
评论
using {}
命名空间的明显好处是它们可以避免命名冲突。但是,通过在类声明中引入整个命名空间,此优势将失效。System 命名空间中的函数完全有可能与你自己的 Bar::MemberFunc 函数冲突。您甚至在示例代码中添加注释“no conflict with this”时注意到这一点。
您显然不想像这样将整个命名空间引入到您的类中:
using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;
而且,您不能将范围更窄的 using 此类语句添加到类声明中。将这些直接放入类声明中是非法的。
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*/);
};
这有三个明显的优势。
- 不介绍整个命名空间的内容。这有助于更轻松地避免命名冲突。
- 在类声明之前,您有一个列表,列出了您的类正常工作所依赖的内容。
- 函数声明是干净的。
如果我错了,请纠正我;我只是简单地测试了一下。很快写了一个例子,它就编译了。
评论
您可以在类声明中使用 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);
};
评论
System::Network::Win32::Sockets
评论