当存在内联命名空间时,如何显式引用封闭的命名空间?
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::pair
和 std::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# 中引用完整的命名空间? [复制]