当存在内联命名空间时,如何显式引用封闭命名空间?
How can I explicitly refer to an enclosing namespace when an inline namespace exists?
请考虑此代码:
#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
。有解决办法吗?
当内联命名空间确实有同名方法 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
调用
一旦看到内联命名空间,就不能明确引用封闭命名空间中定义的符号。
特别是对于您的情况,main
中的限定查找被正确地标记为不明确(正如您自己所说)。请参阅 cppreference 上的最后一点:
Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.
然而,其他人在评论中指出,当您尝试使用 std::pair
时,您可能在工具链调用中面临配置问题。
要解决您的问题,您需要确保调用编译器来编译 C++11 代码,这将带有标志:
-std=c++11
或 -std=c++0x
取决于您的 Clang/GCC
版本
提供更多背景信息:
内联命名空间是 C++11 的一个特性,引入它主要是为了在库中允许 符号版本控制 。然后,C++ 标准库实现可以在嵌套命名空间(使用非标准名称)中定义不同版本的符号,并且根据编译时请求的库版本,工具链将这些嵌套命名空间之一定义为内联。看来您正在使用库的 c++11 版本(因为它在内联命名空间 _1
中定义了一些符号,特别是 pair
),所以实际上在内联命名空间中有符号你要。
我不认为这是可能的;来自 cppreference:
Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.
但是,您所说的这两个定义似乎是从不同的文件中提取的,实际上您描述的情况似乎并不如此。因此,您 "bookmark" 更多的外部定义,以便在需要时能够调用它:
#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
请考虑此代码:
#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
。有解决办法吗?
当内联命名空间确实有同名方法 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
一旦看到内联命名空间,就不能明确引用封闭命名空间中定义的符号。
特别是对于您的情况,main
中的限定查找被正确地标记为不明确(正如您自己所说)。请参阅 cppreference 上的最后一点:
Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.
然而,其他人在评论中指出,当您尝试使用 std::pair
时,您可能在工具链调用中面临配置问题。
要解决您的问题,您需要确保调用编译器来编译 C++11 代码,这将带有标志:
-std=c++11
或 -std=c++0x
取决于您的 Clang/GCC
提供更多背景信息:
内联命名空间是 C++11 的一个特性,引入它主要是为了在库中允许 符号版本控制 。然后,C++ 标准库实现可以在嵌套命名空间(使用非标准名称)中定义不同版本的符号,并且根据编译时请求的库版本,工具链将这些嵌套命名空间之一定义为内联。看来您正在使用库的 c++11 版本(因为它在内联命名空间 _1
中定义了一些符号,特别是 pair
),所以实际上在内联命名空间中有符号你要。
我不认为这是可能的;来自 cppreference:
Qualified name lookup that examines the enclosing namespace will include the names from the inline namespaces even if the same name is present in the enclosing namespace.
但是,您所说的这两个定义似乎是从不同的文件中提取的,实际上您描述的情况似乎并不如此。因此,您 "bookmark" 更多的外部定义,以便在需要时能够调用它:
#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