好吧,这个问题已经发生了一些变化,我想尝试从我正在追求的基本目标开始(重新):
- 创建在 C++ 资源获取和初始化中包装遗留 C 语言实体的库代码,并提供基本或更好的异常保证。
- 使此代码的客户端能够以非常自然的 C++ 方式使用它,而不会为现有代码创建大量开销以将其转换为使用 C++ 包装对象(即自动转换为适当的遗留类型、采用遗留类型的构造函数等) .)
- 限制库代码的命名空间影响。理想情况下,该库将具有多个子命名空间,这些子命名空间提供相关功能,限制使用命名空间 X 类型声明的数量和影响 - 就像 boost 库所做的那样(即使用详细命名空间仅注入用户合理想要的那些符号使用并隐藏那些实现细节;还限制现有符号可能的新含义的范围,以避免用户代码中令人惊讶的隐式转换)
- 要求客户明确请求他们实际想要注入到代码库中的库的那些部分。这与限制包含库标头的影响密切相关。客户端代码应该对编译代码时自动使用库的哪些部分进行名称解析有合理的控制级别。
- 我自己的库代码不应该充满重构脆弱的代码结构。如果库的标头不必不断声明私有 typedef 来访问库的该部分的其余部分,那就太理想了。或者换句话说:我希望我的库能够像我的客户在使用该库时一样直观地编写。除了已明确“使用”的任何其他命名空间之外,名称解析还应包括定义库的命名空间。
我经常遇到这种情况,正在寻找更好的方法......
我有一个类 C,位于命名空间 N 中。C 有一个成员 Free。 C 管理的东西是免费的,并且允许 C 管理新的东西。
有几个全局免费函数。在与 C 相同的命名空间 N 中还有一些辅助函数,其中之一是 free 是 C 管理的东西的辅助函数,名为 free。
所以我们有这样的东西:
namespace N {
void free(THING * thing);
class C
{
public:
... details omitted...
free()
{
free(m_thing); // <- how best to refer to N::free(THING&)
}
}
} // namespace N
我可以使用 N::free(m_thing)。但这对我来说似乎很不幸。是否没有办法引用类范围之外的内容,但又不解析绝对名称空间(相对范围内的一步)?
在我看来,必须命名 N::free 是令人讨厌的,因为如果这是一个独立的函数,则不必这样做。如果类的方法名称碰巧不同(例如 dispose),您也不需要这样做。但因为我使用了相同的名称,所以如果您愿意接受我的类比,我就无法在不指定绝对路径(而不是相对路径)的情况下访问它。
我讨厌绝对路径。它们使得在命名空间中移动东西变得非常脆弱,因此代码重构变得更加难看。另外,如何在函数体中命名事物的规则随着当前的一组规则(据我所知)而变得更加复杂 - 不太规则 - 导致人们期望的东西和作为程序员得到的东西之间的分裂。
有没有更好的方法来访问与类相同的命名空间中的独立函数,而不必绝对命名自由函数?
编辑:
也许我应该举一个不太抽象的例子:
namespace Toolbox {
namespace Windows {
// deallocates the given PIDL
void Free(ITEMIDLIST ** ppidl);
class Pidl
{
public:
// create empty
Pidl() : m_pidl(NULL) { }
// create a copy of a given PIDL
explicit Pidl(const ITEMIDLIST * pidl);
// create a PIDL from an IShellFolder
explicit Pidl(IShellFolder * folder);
...
// dispose of the underlying ITEMIDLIST* so we can be free to manage another...
void Free();
};
因此 ITEMIDLIST* 来自各个地方,并被 CoTaskMemFree() 销毁。我可以引入 Pidl 作为全局名称 - 以及“Windows Shell.h”标头中的所有辅助函数,该标头是我的工具箱库的一部分。
理想情况下,我会根据库中的一些工具的相关内容对它们进行细分 - 在本例中,上述所有工具都与 Windows 中的 COM 编程相关。我选择 Toolbox 作为我的库内容的基本命名空间,并且目前正在考虑将 Toolbox::Windows 用于非常 Windows 的函数、类等。
但 C++ 命名空间和名称解析规则似乎使这变得非常困难(因此出现了这个问题)。创建这样的代码分段非常不自然 - 因为 koenig 查找失败(因为 ITEMIDLIST 不在我的 Toolbox::Windows 命名空间中),而且我无法将其移动到那里!我也不应该。在我看来,该语言应该足够灵活,以允许扩展库(例如我的 Toolbox 库)扩展其他人的代码,而不必将我的扩展注入到他们的命名空间中(在 Win32 和一般广泛的情况下)今天存在的大多数代码都是 GLOBAL NS - 这就是首先创建名称空间的全部目的:避免全局 NS 拥挤/污染/歧义/编程意外)。
所以,我回过头来,有没有更好的方法来做到这一点:扩展现有的代码库,同时不会用我的扩展污染他们的 NS,但仍然允许直观和有用的名称解析,正如人们所期望的那样,如果我的代码在他们的 NS 中,但由我的客户明确引入代码(即我不想随意注入我的代码,但只有在明确请求时才注入)?
另一个想法:如果我具有以下条件,也许可以满足我的上述标准:
using namespace X {
code here...
}
我可以将这样的构造放在任何地方,包括在标头中,并且我不必担心将 X 拖到我的客户代码中,但我将拥有与在根命名空间。