我正在用 C++ 管理套接字地址,我专门研究
::sockaddr_storage
系统库结构,例如:
#include <sys/socket.h>
namespace ns1 {
struct sockaddr_storage : public ::sockaddr_storage {
void set_af(sa_family_t a_af) {
this->ss_family = a_af;
}
};
} // namespace ns1
namespace ns1 {
// Variant 1: this compiles and works as expected
void f1() {
sockaddr_storage ss;
ss.set_af(AF_INET6);
}
} // namespace ns1
namespace ns2 {
// Variant 2: this also compiles and works without errors
void f2() {
ns1::sockaddr_storage ss;
ss.set_af(AF_INET6);
}
} // namespace ns2
using ::ns1::sockaddr_storage;
namespace ns2 {
// Variant 3: with declaring `using` it does not compile
void f3() {
sockaddr_storage ss;
ss.set_af(AF_INET6);
}
} // namespace ns2
int main() {}
对于变体 3,我收到以下错误消息:
example$ g++ -std=c++11 -Wall -Wpedantic -Wextra -Werror -Wuninitialized -Wsuggest-override -Wdeprecated example.cpp
example.cpp:27:14: error: ‘struct ns1::sockaddr_storage’ conflicts with a previous declaration
27 | using ::ns1::sockaddr_storage;
| ^~~~~~~~~~~~~~~~
In file included from /usr/include/x86_64-linux-gnu/sys/socket.h:33,
from example.cpp:1:
/usr/include/x86_64-linux-gnu/bits/socket.h:191:8: note: previous declaration ‘struct sockaddr_storage’
191 | struct sockaddr_storage
| ^~~~~~~~~~~~~~~~
example.cpp: In function ‘void ns2::f3()’:
example.cpp:33:8: error: ‘struct sockaddr_storage’ has no member named ‘set_af’
33 | ss.set_af(AF_INET6);
| ^~~~~~
我希望使用
using ::ns1::sockaddr_storage;
编译器只会对未指定的调用执行此操作。我不想在我的旧代码中使用名称空间名称为所有sockaddr_storage
添加前缀。
为什么编译出错?我该怎么做才能避免它?为什么和 Variant 1 没有冲突?
using-declaration的作用
using ::ns1::sockaddr_storage;
是编译器将进行名称查找,就好像由
::ns1::sockaddr_storage
命名的实体在 using 声明出现的范围内被声明(使用其实际名称)。您如何引用该实体并不重要。 using ns1::sockaddr_storage;
的效果是一样的
因此
using ::ns1::sockaddr_storage;
尝试将名为 sockaddr_storage
的类的声明引入全局命名空间范围,该范围已经声明了一个具有相同名称的类。不可能以任何方式区分两者,所以这总是一个错误。
对于通常的名称查找,
::X
和 X
之间的唯一区别是查找将直接(且仅)在全局名称空间范围内使用前一种语法查找 X
,而在后一种语法中 X
是从内到外依次搜索所有包含的范围。然后是通过 using 声明还是直接声明找到该名称是无关紧要的。无论哪种方式,它们都被视为查找结果集的一部分。
(合格名称和非合格名称之间还有一些其他区别,例如函数调用的参数相关查找等)
用户 17732522 的有用答案暗示了显而易见的解决方案。谢谢 :-) 我将
using
语句移动到命名空间 ns2
:
namespace ns2 {
// Variant 3
using ::ns1::sockaddr_storage;
void f3() {
sockaddr_storage ss;
ss.set_af(AF_INET6);
}
} // namespace ns2