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

How can I explicitly refer to an enclosing namespace when an inline namespace exists?

本文关键字:命名空间 引用 何显式 存在      更新时间:2023-10-16

请考虑以下代码:

#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。有解决办法吗?

我认为这是不可能的;从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

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

特别是在您的情况下,main中的限定查找被正确地标记为模棱两可(正如您自己所说)。参见cppreference的最后一点:

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


然而,其他人在评论中指出,当您尝试使用std::pair时,您可能面临工具链调用中的配置问题。

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

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

给出进一步的上下文:
内联命名空间是c++ 11的一个特性,主要是为了允许库中的符号版本控制而引入的。然后,c++标准库实现可以在嵌套命名空间中定义不同版本的符号(使用非标准名称),并且根据编译时请求的库版本,工具链将这些嵌套命名空间中的一个定义为内联的。似乎您正在使用c++11版本的库(因为它定义了一些符号,特别是pair,在内联命名空间_1中),所以在内联命名空间中实际上有您想要的符号。

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

But You can try this;

#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
}
  1. namespace Foo中的方法包装到namespace A中,然后将inline中的namespace A中。
  2. Bar中删除内联。

现在如果你调用Foo::ool();,它将调用inline A::ool()
Bar::ool可以被Foo::Bar::ool调用