什么是内联命名空间? [英] What are inline namespaces for?

查看:129
本文介绍了什么是内联命名空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 11允许内联命名空间,其所有成员也自动在包含的命名空间中。我不能想到任何有用的应用程序 - 可以有人请给出一个简单,简洁的例子,其中需要 inline命名空间,它是最惯用的解决方案?



(另外,我不清楚当命名空间声明 inline 在一个但不是所有的声明,可能会生活在不同的文件中。)这是不是麻烦?)

解决方案

内联命名空间是一个库版本控制功能,类似于符号版本化,而是纯粹在C ++ 11级别(即跨平台)实现,而不是特定二进制可执行格式(即平台特定)的特征。



这是一种机制,通过它,库作者可以使嵌套的命名空间看起来好像所有的声明都在周围的命名空间中(内联命名空间可以嵌套,所以更多嵌套名称渗透到第一个非内联命名空间,并且看起来好像他们的声明在两者之间的任何命名空间中)。



作为一个例如,考虑向量的STL实现。如果我们有从C ++开始的内联命名空间,那么在C ++ 98中,头< vector> 可能看起来像这样:

 命名空间std {

#if __cplusplus< 1997L // pre-standard C ++
inline
#endif

命名空间pre_cxx_1997 {
template< class T> __vector_impl; // implementation class
template< class T> //例如w / o分配器参数
类向量:__vector_impl< T> {// private inheritance
// ...
};
}
#if __cplusplus> = 1997L // C ++ 98/03或更高版本
//(ifdef' out out b / c它可能使用新语言
/ /特征,一个前C ++ 98编译器会窒息)
#if __cplusplus == 1997L // C ++ 98/03
inline
#endif

namespace cxx_1997 {

// std :: vector现在有一个分配器参数
template< class T,class Alloc = std :: allocator< T> >
类向量:pre_cxx_1997 :: __vector_impl< T> {//旧的impl仍然是好的
// ...
};

//和向量< bool>是特殊的:
template< class Alloc = std :: allocator< bool> >
class vector< bool> {
// ...
};

};

#endif // C ++ 98/03或更高版本

} //命名空间std

根据 __ cplusplus 的值,一个或另一个向量选择实现。如果你的代码库是在前C ++ 98次编写的,并且你发现C $ 98版本的向量在升级你的编译器时会导致麻烦, all你需要在你的代码库中找到 std :: vector 的引用,并用 std :: pre_cxx_1997 :: vector c>。



进入下一个标准,STL供应商只是重复该过程,为 std引入一个新的命名空间:: vector emplace_back 支持(需要C ++ 11),并且内联一个iff __ cplusplus == 201103L



好的,为什么我需要一个新的语言功能呢?我已经可以做到以下有同样的效果,不?

 命名空间std {

命名空间pre_cxx_1997 {
// ...
}
#if __cplusplus< 1997L // pre-standard C ++
using namespace pre_cxx_1997;
#endif

#if __cplusplus> = 1997L // C ++ 98/03或更高版本
//(ifdef' out out b / c it it uses using new language
//特性,一个前C ++ 98编译器会窒息)

命名空间cxx_1997 {
// ...
};
#if __cplusplus == 1997L // C ++ 98/03
using namespace cxx_1997;
#endif

#endif // C ++ 98/03或更高版本

} //命名空间std

根据 __ cplusplus 的值,我得到一个或另一个实现。 / p>

你几乎是正确的。



考虑下面有效的C ++ 98用户代码允许完全专门化在C ++ 98中的命名空间 std 中的模板):

  //我不相信我的STL供应商做这个优化,所以强制这些
//特殊化自己:
namespace std {
template<>
class vector< MyType> :my_special_vector< MyType> {
// ...
};
模板<>
class vector< MyOtherType> :my_special_vector< MyOtherType> {
// ...
};
// ... etc ...
} //命名空间std

这是完全有效的代码,其中用户为一组类型提供自己的向量实现,其中她显然知道比在STL的(她的副本)中发现的更有效的实现。



但是:当专门化模板时,你需要在声明的命名空间中这样做。标准表示向量在命名空间 std 中声明,因此这是用户正确地期望专门化该类型的地方。



与非版本化命名空间 std 或与C ++ 11内联命名空间功能,但不与使用使用命名空间< ;嵌套> ,因为暴露了其中定义向量的真实命名空间不是 std 直接。



还有其他漏洞,你可以通过它检测嵌套的命名空间(见下面的注释),但内联命名空间将它们全部插入。这就是它的所有。对于未来非常有用,但是AFAIK标准没有规定自己的标准库的内联命名空间名称(我希望被证明是错误的,虽然),所以它只能用于第三方库,而不是标准本身(除非编译器供应商同意命名方案)。


C++11 allows inline namespaces, all members of which are also automatically in the enclosing namespace. I cannot think of any useful application of this -- can somebody please give a brief, succinct example of a situation where an inline namespace is needed and where it is the most idiomatic solution?

(Also, it is not clear to me what happens when a namespace is declared inline in one but not all declarations, which may live in different files. Isn't this begging for trouble?)

解决方案

Inline namespaces are a library versioning feature akin to symbol versioning, but implemented purely at the C++11 level (ie. cross-platform) instead of being a feature of a specific binary executable format (ie. platform-specific).

It is a mechanism by which a library author can make a nested namespace look and act as if all its declarations were in the surrounding namespace (inline namespaces can be nested, so "more-nested" names percolate up all the way to the first non-inline namespace and look and act as if their declarations were in any of the namespaces in between, too).

As an example, consider the STL implementation of vector. If we had inline namespaces from the beginning of C++, then in C++98 the header <vector> might have looked like this:

namespace std {

#if __cplusplus < 1997L // pre-standard C++
    inline
#endif

    namespace pre_cxx_1997 {
        template <class T> __vector_impl; // implementation class
        template <class T> // e.g. w/o allocator argument
        class vector : __vector_impl<T> { // private inheritance
            // ...
        };
    }
#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)
#  if __cplusplus == 1997L // C++98/03
    inline
#  endif

    namespace cxx_1997 {

        // std::vector now has an allocator argument
        template <class T, class Alloc=std::allocator<T> >
        class vector : pre_cxx_1997::__vector_impl<T> { // the old impl is still good
            // ...
        };

        // and vector<bool> is special:
        template <class Alloc=std::allocator<bool> >
        class vector<bool> {
            // ...
        };

    };

#endif // C++98/03 or later

} // namespace std

Depending on the value of __cplusplus, either one or the other vector implementation is chosen. If your codebase was written in pre-C++98 times, and you find that the C++98 version of vector is causing trouble for you when you upgrade your compiler, "all" you have to do is to find the references to std::vector in your codebase and replace them by std::pre_cxx_1997::vector.

Come the next standard, and the STL vendor just repeats the procedure again, introducing a new namespace for std::vector with emplace_back support (which requires C++11) and inlining that one iff __cplusplus == 201103L.

OK, so why do I need a new language feature for this? I can already do the following to have the same effect, no?

namespace std {

    namespace pre_cxx_1997 {
        // ...
    }
#if __cplusplus < 1997L // pre-standard C++
    using namespace pre_cxx_1997;
#endif

#if __cplusplus >= 1997L // C++98/03 or later
                         // (ifdef'ed out b/c it probably uses new language
                         // features that a pre-C++98 compiler would choke on)

    namespace cxx_1997 {
        // ...
    };
#  if __cplusplus == 1997L // C++98/03
    using namespace cxx_1997;
#  endif

#endif // C++98/03 or later

} // namespace std

Depending on the value of __cplusplus, I get either one or the other of the implementations.

And you'd be almost correct.

Consider the following valid C++98 user code (it was permitted to fully specialize templates that live in namespace std in C++98 already):

// I don't trust my STL vendor to do this optimisation, so force these 
// specializations myself:
namespace std {
    template <>
    class vector<MyType> : my_special_vector<MyType> {
        // ...
    };
    template <>
    class vector<MyOtherType> : my_special_vector<MyOtherType> {
        // ...
    };
    // ...etc...
} // namespace std

This is perfectly valid code where the user supplies its own implementation of a vector for a set of type where she apparently knows a more efficient implementation than the one found in (her copy of) the STL.

But: When specializing a template, you need to do so in the namespace it was declared in. The Standard says that vector is declared in namespace std, so that's where the user rightfully expects to specialize the type.

This code works with a non-versioned namespace std, or with the C++11 inline namespace feature, but not with the versioning trick that used using namespace <nested>, because that exposes the implementation detail that the true namespace in which vector was defined was not std directly.

There are other holes by which you could detect the nested namespace (see comments below), but inline namespaces plug them all. And that's all there is to it. Immensely useful for the future, but AFAIK the Standard doesn't prescribe inline namespace names for its own standard library (I'd love to be proven wrong on this, though), so it can only be used for third-party libraries, not the standard itself (unless the compiler vendors agree on a naming scheme).

这篇关于什么是内联命名空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆