如何在C++11中为全局命名空间创建别名

12

简化版: 在C++11中如何为根(全局)命名空间定义别名?可能看起来像:

namespace root_namespace = ::;

其中上述裸形式的作用域解析运算符是全局命名空间的某个句柄的占位符。我在GCC Internals Manual中读到:

......[编译器的]整个中间表示的根是变量global_namespace。这是在C++源代码中使用::指定的命名空间......全局命名空间的名称是::,尽管在C++中全局命名空间没有名称。

PS编辑:针对迄今为止的回答者,我添加了一个痛苦漫长的形式来解决一些问题,因为它可能会澄清一些事情。如果您看到我们互相交谈而不是面对面交谈,请深入探究。


详细版: 下面是其潜在用途的示例。 如果不令人满意,那么是的,这是一个学术问题;请参阅此后的痛苦漫长的形式

想象一下,你的老板某天闯进来说:“我刚读了一本关于后实证主义的书。 删除namespace ObjectiveReality。”在下面的代码中,您只需省略我标记为/*->/*<-*/的行即可。您可以为中间嵌套级别执行此操作;但是,我不确定如何定义全局范围的namespace current_authority以允许简单省略第一个非全局命名空间。

#include <iostream>
#include <iomanip>


// ...
using cat_is_alive = std::true_type ; // because I like cats
using cat_is_alive = ::cat_is_alive ; // seems to work, see `g++ -v` below
// ...


// ASIDE: I originally had `namespace higher_authority = COMPILER ;` as a comment, but changed it for simpler chaining closure

// The next two lines are the crux of my question...

namespace higher_authority = global_namespace ;
namespace current_authority = global_namespace ; // a.k.a. the naked ::

// If the above two lines defined aliases for the (unnamed) global namespace, then the suggested elisions/replacements work...

/* -> */
namespace ObjectiveReality {
/* <- */
// Simplest fix: replace with `using ObjectiveReality = current_authority ;`
//   (Otherwise, a few other changes are necessary)

    namespace higher_authority = current_authority ;
    namespace current_authority = ObjectiveReality ;

    using cat_is_alive = higher_authority::cat_is_alive ;

    namespace EntangledObserver {

        namespace higher_authority = current_authority ;
        namespace current_authority = EntangledObserver ;

        using cat_is_alive = higher_authority::cat_is_alive ;
    } ;
/* -> */
} ;
/* <- */


int main( int argc, char** argv ) {

    std::cout
        << "It is "
        << ObjectiveReality::EntangledObserver::cat_is_alive::value
       << " that the cat is alive." << std::endl ;

    return 0 ;
}


// EOF

如果需要编译器信息:

$ g++ -std=c++11 -v

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.7/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-11precise2' 
--with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs 
--enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 
--enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib 
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib
--enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin
--enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686
--with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release 
--build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-11precise2) 

痛苦的长表单:作为对“从嵌套命名空间开始”的一些答案的回应,请注意“HOME!”不可访问,并且我可能没有在团队中手动选择命名空间的奢侈。

//
// alice.cpp
//


#include <iostream>
#include <type_traits>


/////
///// The Setup
/////

//
// One-and-a-half macros
//

// BOO! Get rid of this case!
#define ENABLE_SUBSPACE_1( namespace_name ) \
    namespace namespace_name { \
    namespace last_namespace = ::namespace_name ; \
    namespace this_namespace = ::namespace_name ;

// YEAH! Instead, define 'namespace this_namespace = :: ;' and then...
#define ENABLE_SUBSPACE( namespace_name ) \
    namespace namespace_name { \
    namespace last_namespace = this_namespace ; \
    namespace this_namespace = last_namespace::namespace_name ;

//
// Some characters
//

struct dorothy {
    static constexpr auto obvious_statement = "There's no place like " ;
} ;

struct rabbit {
    template< typename T >
    static constexpr char const* says( T ) {
        return T::value ? "I'm late!" : "I'm late, but I ditched that addled girl." ;
    }
} ;

struct alice {

    using blue_pill = std::false_type ;
    static constexpr auto where_am_i = "HOME!" ;
} ;


/////
///// The Central Structure
/////

ENABLE_SUBSPACE_1( oxford_england ) // {

    using has_strangers_with_candy = std::true_type ;

    struct alice {
        using blue_pill = this_namespace::has_strangers_with_candy ;
        static constexpr auto where_am_i = "Uncle Charles' picnic blanket." ;
    } ;

ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
    using has_strangers_with_candy = std::false_type ; ///// Different...
ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
    struct alice { ///// Different...
        using blue_pill = has_strangers_with_candy ;
        static constexpr auto where_am_i = "needing a fix." ;
    } ;
ENABLE_SUBSPACE( rabbit_hole ) // {
    struct rabbit { using is_late = typename alice::blue_pill ; } ;
    struct alice : last_namespace::alice { ///// Different...
        static constexpr auto where_am_i = "an empty rabbit hole." ;
    } ;
} ; // END rabbit_hole
} ; // END rabbit_hole
} ; // END rabbit_hole
} ; // END rabbit_hole
} ; // END rabbit_hole
} ; // END rabbit_hole
} ; // END oxford_england


/////
///// Snarky Output
/////

int main( int argc, char** argv ) {

    std::cout << std::endl
        << dorothy::obvious_statement
        << alice::where_am_i
        << std::endl ; // There's no place like HOME!

    std::cout
        << dorothy::obvious_statement
        << oxford_england::rabbit_hole::rabbit_hole::rabbit_hole::rabbit_hole::rabbit_hole::alice::where_am_i
        << std::endl ; // There's no place like needing a fix.

    std::cout
        << dorothy::obvious_statement
        << oxford_england::rabbit_hole::rabbit_hole::rabbit_hole::rabbit_hole::rabbit_hole::rabbit_hole::alice::where_am_i
        << std::endl ; // There's no place like an empty rabbit hole.

    std::cout << std::endl
        << rabbit::says(
            oxford_england::
                rabbit_hole::
                    rabbit_hole::
                        rabbit_hole::
                            rabbit_hole::
                                rabbit_hole::rabbit::is_late()
        ) << std::endl ; // I'm late!
    std::cout
        << rabbit::says(
            oxford_england::
                rabbit_hole::
                    rabbit_hole::
                        rabbit_hole::
                            rabbit_hole::
                                rabbit_hole:: // NOTE : alice::blue_pill is false_type
                                    rabbit_hole::rabbit::is_late() // ... not this time ; Alice is crashing.
        ) << std::endl ; // I'm late, but I ditched that addled girl.

    std::cout << std::endl
        << dorothy::obvious_statement
        << oxford_england::
                rabbit_hole:: // 1
                    rabbit_hole:: // 2
                        rabbit_hole:: // 3
                            rabbit_hole:: // 4
                                rabbit_hole:: // 5
                                    rabbit_hole:: // rabbit_hole #6
                                last_namespace:: // rabbit_hole #5
                            last_namespace:: // rabbit_hole #4
                        last_namespace:: // rabbit_hole #3
                    last_namespace:: // rabbit_hole #2
                last_namespace:: // rabbit_hole #1
            last_namespace::alice::where_am_i // oxford_england
        << std::endl ; // There's no place like Uncle Charles' picnic blanket.
    std::cout
        << dorothy::obvious_statement
        << oxford_england::
                rabbit_hole::
                    rabbit_hole::
                        rabbit_hole::
                            rabbit_hole::
                                rabbit_hole::
                                    rabbit_hole::
                                last_namespace::
                            last_namespace::
                        last_namespace:: // 3
                    last_namespace:: // 2
                last_namespace:: // 1
            last_namespace:: // oxford
        last_namespace::alice::where_am_i // not the global namespace!
        << ".. but I'd rather be " << ::alice::where_am_i // the global namespace.
        << std::endl ; // There's no place like Uncle Charles' picnic blanket... but I'd rather be HOME!

    std::cout << std::endl ;
    return 0 ;
}


/////
///// EOF
/////


/* Compiled with:
    `g++ -std=c++11 -o alice alice.cpp`
*/

/* Output of `alice` :

There's no place like HOME!
There's no place like needing a fix.
There's no place like an empty rabbit hole.

I'm late!
I'm late, but I ditched that addled girl.

There's no place like Uncle Charles' picnic blanket.
There's no place like Uncle Charles' picnic blanket... but I'd rather be HOME!

*/

colon - Kerrek SB
为什么你不能在全局范围内添加 using namespace ObjectiveReality; 呢? - Kerrek SB
2
对于C++命名空间的好奇哲学看法,点个赞。 - nneonneo
1
@Kerrek - 我从几次 PHP 错误中学到了 PAAMAYIM_NEKUDOTAYIM。这是解释器称呼它的方式;vive la différence,oy! - Louis Carole
让老板去看心理医生吧。;-)(显然我对实证主义问题有坚定的立场。) - Konrad Rudolph
2个回答

2
今日免费次数已满, 请开通会员/明日再来
7.3.2   Namespace alias
A namespace-alias-definition declares an alternate name for a namespace according to the following grammar:
namespace-alias:
    identifier 
namespace-alias-definition:
    namespace identifier = qualified-namespace-specifier ;
qualified-namespace-specifier:
    ::_opt nested-name-specifier_opt namespace-name

请注意,::是可选的,但命名空间名称不是。
然而,你是否可以使用除全局命名空间以外的其他内容作为命名空间堆栈的起点,并仍然遵循你所概述的模式呢?
还要注意,当你删除ObjectiveReality时,你的示例确实需要编辑一些额外的行。
namespace current_authority = ObjectiveReality ;

并且:

<< ObjectiveReality::EntangledObserver::cat_is_alive::value

使用命名空间"something"代替全局命名空间作为命名空间栈的根时,您的示例看起来是这样的。

#include <iostream>
#include <iomanip>


// ...                                                                                                                                                                                                                                                                                                                                                                    
namespace something {
  using cat_is_alive = std::true_type ; // because I like cats                                                                                                                                                                                                                                                                                                            
}
using namespace something;
// ...                                                                                                                                                                                                                                                                                                                                                                    


// ASIDE: I originally had `namespace higher_authority = COMPILER ;` as a comment, but changed it for simpler chaining closure                                                                                                                                                                                                                                            

// The next two lines are the crux of my question...                                                                                                                                                                                                                                                                                                                      

namespace higher_authority = something;
namespace current_authority = something;                                                                                                                                                                                                                                                                                                         

// If the above two lines defined aliases for the (unnamed) global namespace, then the suggested elisions/replacements work...                                                                                                                                                                                                                                            

/* -> */
namespace ObjectiveReality {
  /* <- */
  // Simplest fix: replace with `using ObjectiveReality = current_authority ;`                                                                                                                                                                                                                                                                                            
  //   (Otherwise, a few other changes are necessary)                                                                                                                                                                                                                                                                                                                     

  namespace higher_authority = current_authority ;
  namespace current_authority = ObjectiveReality ;

  using cat_is_alive = higher_authority::cat_is_alive ;

  namespace EntangledObserver {

    namespace higher_authority = current_authority ;
    namespace current_authority = EntangledObserver ;

    using cat_is_alive = higher_authority::cat_is_alive ;
  } ;
  /* -> */
} ;
/* <- */


int main( int argc, char** argv ) {

  std::cout
    << "It is "
    << ObjectiveReality::EntangledObserver::cat_is_alive::value
    << " that the cat is alive." << std::endl ;

  return 0 ;
}


// EOF

你呼唤了我。实际上,我重写了cat_is_alive作为一种类型,试图掩盖我的罪恶行径; 我需要仔细思考你的候选答案,感谢你提供的示例和语法!同时:是否存在合法的存在原因来_禁止_全局命名空间别名? - Louis Carole
仍在犹豫 - 但是,桶里有个洞。来自Soverman的话,“你不可以使用除全局命名空间以外的其他东西作为你的命名空间堆栈的起始点,并仍然遵循你已经概述的模式吗?” 我的宏伟计划是修复n = 1的基本情况。 n => n+1很好,但抽象层次并不是解决方法,对吧? - Louis Carole
2
我认为没有任何存在主义的理由阻止别名全局命名空间。据我所知,这只是语言定义的方式。有时候C++有点荒谬主义。您能解释一下为什么在您的情况下使用命名空间而不是全局命名空间作为n=1基本情况不起作用吗?我没有理解您的抽象级别问题。 - Soverman
我认为也许是时候提出一个新问题了。原始问题很清楚:“如何给全局命名空间取别名?”,并且有一个明确的答案:“你不能”。现在,我认为新问题是这样的:“在某些允许编辑的代码约束条件下,如何模拟类似堆栈的命名空间结构。”为了得到这个问题的好答案,我认为您需要更明确地说明由于团队合作和只能修改部分代码而产生的约束条件。您痛苦的长表单似乎可以工作,但违反了这些约束条件。 - Soverman

1
我不知道有直接别名默认命名空间的方法,但是作为一种解决方法,您可以使用宏(假设您愿意接受宏名称与不相关符号冲突的情况)。
#define root_namespace

使用方法:

root_namespace::cat_is_alive

正如 Mooing Duck 正确指出的那样,这种 hack 无法与 using 子句一起使用。

5
这很巧妙,但是……using namespace root_namespace; - Mooing Duck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接