25

请考虑以下代码:

#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?

我发现处于类似位置的人试图了解发生了什么,但我没有看到这种情况的解决方案。

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

4

3 回答 3

13

我认为这是不可能的;来自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
于 2015-08-25T09:12:30.483 回答
5

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

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

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


然而,评论中是否有其他人指出,当您尝试使用std::pair.

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

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

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

于 2015-08-25T09:10:24.613 回答
2

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
}
  1. 将方法包装namespace Foonamespace Atheninline namespace A中。
  2. 从 中删除内联Bar

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

于 2015-08-25T09:08:40.133 回答