首页 文章

什么是内联命名空间?

提问于
浏览
301

C 11允许 inline namespace ,其所有成员也自动在封闭 namespace 中 . 我想不出任何有用的应用 - 有人可以给出一个简短,简洁的例子,说明需要 inline namespace 这是最惯用的解决方案吗?

(另外,我不清楚当 namespace 在一个但不是所有声明中声明 inline 时会发生什么,它可能存在于不同的文件中 . 这不是在乞求麻烦吗?)

2 回答

  • 308

    内联名称空间是类似于symbol versioning的库版本控制功能,但纯粹在C 11级(即跨平台)实现,而不是特定二进制可执行格式(即特定于平台)的功能 .

    它是一种机制,通过该机制,库作者可以使嵌套的命名空间看起来并且就好像它的所有声明都在周围的命名空间中一样(内联命名空间可以嵌套,因此“更多嵌套”的名称一直渗透到第一个非命名空间-inline命名空间,看起来和行为就好像它们的声明也在它们之间的任何命名空间中) .

    例如,考虑 vector 的STL实现 . 如果我们从C的开头有内联命名空间,那么在C 98中, Headers <vector> 可能看起来像这样:

    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
    

    根据 __cplusplus 的值,选择一个或另一个 vector 实现 . 如果您的代码库是在C-98之前编写的,并且您发现在升级编译器时C28版本的 vector 会给您带来麻烦,那么您需要做的是在代码库中找到对 std::vector 的引用并替换他们是 std::pre_cxx_1997::vector .

    进入下一个标准,STL供应商再次重复该过程,为 std::vector 引入一个新的命名空间,支持 emplace_back (需要C11)并内联一个iff __cplusplus == 201103L .

    好的,为什么我需要一个新的语言功能呢?我已经可以做以下事情来产生同样的效果,不是吗?

    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
    

    根据 __cplusplus 的值,我得到一个或另一个实现 .

    你几乎是正确的 .

    考虑以下有效的C 98用户代码(允许完全专门化C98中名称空间 std 中的模板):

    // 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
    

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

    但是:在专门化模板时,您需要在声明它的名称空间中执行此操作 . 标准说 vector 在名称空间 std 中声明,因此用户正确期望专门化该类型 .

    此代码适用于非版本化命名空间 std ,或使用C 11内联命名空间功能,但不适用于使用 using namespace <nested> 的版本控制技巧,因为这会公开实现详细信息,即定义 vector 的真实命名空间不直接 std .

    您可以通过其他漏洞检测嵌套命名空间(请参阅下面的注释),但内联命名空间会将它们全部插入 . 这就是它的全部内容 . 对于未来非常有用,但AFAIK标准没有规定其自己的标准库的内联命名空间名称(尽管我喜欢被证明是错误的),因此它只能用于第三方库,而不是标准本身(除非编译器供应商同意命名方案) .

  • 59

    http://www.stroustrup.com/C++11FAQ.html#inline-namespace(由Bjarne Stroustrup编写并维护的文档,您认为应该了解大多数C 11功能的大多数动机 . )

    据此,它允许版本化以实现向后兼容性 . 您定义了多个内部命名空间,并使最新的命名空间 inline . 或者无论如何,对于不关心版本控制的人来说是默认的 . 我想最新的版本可能是未来或最新版本,但尚未默认 .

    给出的例子是:

    // file V99.h:
    inline namespace V99 {
        void f(int);    // does something better than the V98 version
        void f(double); // new feature
        // ...
    }
    
    // file V98.h:
    namespace V98 {
        void f(int);    // does something
        // ...
    }
    
    // file Mine.h:
    namespace Mine {
    #include "V99.h"
    #include "V98.h"
    }
    
    #include "Mine.h"
    using namespace Mine;
    // ...
    V98::f(1);  // old version
    V99::f(1);  // new version
    f(1);       // default version
    

    我没有't immediately see why you don'将 using namespace V99; 置于命名空间 Mine 内,但我不喜欢委员会的动机 .

相关问题