在 C++ 中,未命名的命名空间相当于:
namespace $$$$ {
//something
}
using namespace $$$$;
其中 $$$$ 是某种唯一标识符。未命名的命名空间对于不应该在编译单元之外看到的代码很有用。
到目前为止还不错,但是最近我开始用模板编写一些代码,这些代码必须位于标头中,因此使用未命名的命名空间没有多大意义,因为仅仅包含标头就会使隔离效果失效。
那么问题是,在这种情况下建议的方法是什么?我开始使用名为 Private 的命名空间。它并不能真正阻止任何想要使用内部标识符的人,但至少它减少了 id“Private”的名称冲突。
还有更好的方法吗?有建议吗?
坚持使用您的
Private
namespace
(或使用更流行的 detail
)。请记住,C++ 访问机制背后的主要思想是使滥用它们变得困难,而不是不可能。保护自己免受意外事故,而不是恶意攻击。
如果您渴望这种隔离,为什么不使用旧的好文件-
static
?它未被弃用:
template <typename T>
static void foo()
{}
int main()
{
foo<char>();
}
话又说回来,如果您只需要在一个翻译单元内使用
foo
,那么您可能只将其包含在该翻译单元内的标头中,然后无论它是否“在标头中”都无关紧要。因此,只需不要将模板包含在其他翻译单元中,您就已经基本上实现了隔离的目标。
为了真正保证所有可能的实例化(即包括您在本TU中创建的实例)的隔离,请如上所述使用
static
或仅使用detail
命名空间记录您的意图。
在标头中隐藏模板代码实现的最常用方法是将实现放入名为
detail
的命名空间中。
例如:
namespace cpputil { // my c++ utility library namespace
namespace detail { // implementation details of this libraries headers go here
// a functor private to the library
template<class T>
struct private_functor {
private_functor(const T& t) : _t(t) {}
void write(std::ostream& os) const { _t.write(os); }
private:
const T& _t;
};
// an extension to std::ostream::operator<<
template<class T>
std::ostream& operator<<(std::ostream& os, const private_functor<T>& pf)
{
pf.write(os);
return os;
}
}
/// a public template function that is designed to allow an object to be emitted to a stream
/// returns a function object that calls T::write(std::ostream&) when placed into an
/// output stream
template<class T>
detail::private_functor emit(const T& t) {
return detail::private_functor<T>(t);
}
}
// can be used like this:
int main() {
struct S {
void write(std::ostream& os) const { os << "{I am an S}"; }
};
std::cout << cpputil::emit(S) << std::endl;
return 0;
}