在 C++ 中使用不同的命名空间时如何避免错误“与先前的声明冲突”?

问题描述 投票:0回答:2

我正在用 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 没有冲突?

c++ struct namespaces
2个回答
2
投票

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 声明还是直接声明找到该名称是无关紧要的。无论哪种方式,它们都被视为查找结果集的一部分。

(合格名称和非合格名称之间还有一些其他区别,例如函数调用的参数相关查找等)


0
投票

用户 17732522 的有用答案暗示了显而易见的解决方案。谢谢 :-) 我将

using
语句移动到命名空间
ns2
:

namespace ns2 {
// Variant 3

using ::ns1::sockaddr_storage;

void f3() {
sockaddr_storage ss;
ss.set_af(AF_INET6);
}
} // namespace ns2
© www.soinside.com 2019 - 2024. All rights reserved.