当存在内联命名空间时,如何显式引用封闭的命名空间?

Posted

技术标签:

【中文标题】当存在内联命名空间时,如何显式引用封闭的命名空间?【英文标题】:How can I explicitly refer to an enclosing namespace when an inline namespace exists? 【发布时间】:2015-11-18 20:53:32 【问题描述】:

请考虑以下代码:

#include <iostream>

namespace Foo

    void ool()  // Version A
    
        std::cout << "Foo::ool" << std::endl;
    

    inline namespace Bar
        void ool() // Version B
        
            std::cout << "Foo::Bar::ool" << std::endl;
        
    



int main()

    Foo::ool();  // <- error

Clang 和 G++ 都正确地将 Foo::ool 标记为模棱两可。我可以毫无问题地调用Foo::Bar::ool,但是有没有办法在不更改其声明的情况下调用版本 A?

我发现有类似情况的人试图了解会发生什么,但我没有找到解决这种情况的方法。

我处于这种情况是因为我有一个项目,其中包含 std::__1::pairstd::pair 的声明,在不同的地方进行,std::__1 是一个内联命名空间。我需要代码明确指向std::pair。有解决办法吗?

【问题讨论】:

也许在引入引用std::pair的__1::pair之前定义一个别名模板? 你确定你看的不是this problem吗? (基本上,解决方案是将-std=c++0x(或与较新的编译器类似)添加到编译选项中。)您使用的是什么编译器版本和设置? utnapistim:你是对的。对于我的具体情况,我遇到过这种解决方法,但它让我很好奇如何在一般情况下解决这种具体的歧义。我认为解决方案在我的情况下更多在于 std=libstdc++ 但它确实解决了我的编译问题,谢谢! 【参考方案1】:

我认为这是不可能的;来自cppreference:

检查封闭命名空间的限定名称查找将包括内联命名空间中的名称,即使封闭命名空间中存在相同的名称。

但是,您似乎实际上并不处于您描述的情况,因为您说这两个定义是从不同的文件中提取的。因此,您可以“标记”更多外部定义,以便能够在需要时调用它:

#include <iostream>

// Equivalent of first include
namespace Foo
    void ool()  // Version A
    
        std::cout << "Foo::ool" << std::endl;
    


const auto& foo_ool = Foo::ool;

// Equivalent of second include
namespace Foo
    inline namespace Bar
        void ool() // Version B
        
            std::cout << "Foo::Bar::ool" << std::endl;
        
    


int main()

    foo_ool(); // Works

如果您要为类型添加书签,则一个简单的using 指令就足够了。您的等效代码如下所示:

#include <my_first_include>

// bookmark code

#include <my_second_include>

// rest of the code

【讨论】:

谢谢。我觉得奇怪的是,编译器会默默地接受使用新的内联定义重载一个类。封闭命名空间中的 Foo::ool 函数变得完全无法实现。在我看来,这种行为至少应该触发一个警告。但感谢书签技巧。这是最接近这个问题的解决方案。【参考方案2】:

一旦看到内联命名空间,您就不能明确地引用封闭命名空间中定义的符号。

特别是对于您的情况,main 中的合格查找被正确地标记为模棱两可(正如您自己所说)。看cppreference的最后一点:

检查封闭命名空间的限定名称查找将包括内联命名空间中的名称,即使封闭命名空间中存在相同的名称。


然而,在 cmets 中还有其他人指出,当您尝试使用 std::pair 时,您可能在工具链调用中遇到配置问题

要解决您的问题,您需要确保调用编译器来编译 C++11 代码,这将带有标志:

-std=c++11-std=c++0x 取决于您的 Clang/GCC 版本

提供更多背景信息: 内联命名空间是 C++11 的一个特性,主要是为了允许库中的符号版本控制而引入。然后,C++ 标准库实现可以在嵌套命名空间(具有非标准名称)中定义不同版本的符号,并且根据编译时请求的库版本,工具链将这些嵌套命名空间之一定义为内联。看来您正在使用该库的 c++11 版本(因为它在内联命名空间 _1 中定义了一些符号,特别是 pair),因此实际上您想要的内联命名空间中有符号。

【讨论】:

是的,我实际上以这种方式解决了我目前的问题,但我想知道如何以更通用的方式解决它。无论如何,感谢您指出这些。 @YvesQuemener 从语义上讲,您不需要到达 封闭 符号:如果您实际上在同一个命名空间中定义了多次相同的符号(模重载)(直接编写,通过 using 声明,或通过 inlines 命名空间),问题是多重声明本身,而不是如何解决它们:) 是的,但如果问题在于符号重载,为什么编译器在发生这种情况时没有警告呢?毕竟,它确实会在同一范围内发出重复定义的错误。【参考方案3】:

当内联命名空间确实有同名的方法 ool 时,我认为您不能含糊地引用 ool

但是你可以试试这个;

#include <iostream>

namespace Foo

    inline namespace A 
        void ool()  // Version A
        
            std::cout << "Foo::ool" << std::endl;
        
    

    namespace Bar
        void ool() // Version B
        
            std::cout << "Foo::Bar::ool" << std::endl;
        
    



int main()

    Foo::ool();  // no error

    namespace Foo 中的方法包装在namespace A 然后inline namespace A。 从Bar 中删除内联。

现在,如果您拨打电话Foo::ool();,它将调用inline A::ool()Bar::ool 可以由Foo::Bar::ool 调用

【讨论】:

以上是关于当存在内联命名空间时,如何显式引用封闭的命名空间?的主要内容,如果未能解决你的问题,请参考以下文章

寻求对内联命名空间的澄清

当存在同名的子命名空间时,如何在 c# 中引用完整的命名空间? [复制]

为啥内联未命名的命名空间?

[C/C++]C++的命名空间,缺省参数,引用,auto关键字,内联函数等

内联命名空间中对命名空间的不明确引用

C++入门(命名空间缺省参数函数重载引用内联函数)