c++ - 由于使用声明导致字节和歧义符号?

标签 c++ scope namespaces c++17

我们是一个C++ 库。多年来,我们在全局命名空间中使用 typedef unsigned char byte;。用户程序和其他库提供了 byte 的兼容定义,因此没有问题。

C++17 添加了 std::byte 并改变了字节的语义。现在我们需要通过避免全局 namespace 污染来更加卫生;我们需要将自己与 std::byte 隔离开来。我们的更改是将我们的 byte 移到我们的命名空间中。

在测试更改的影响时,我们目睹了意外的失败。下面的程序没有遵循最佳实践(根据 Herb Sutter 在 Migrating to Namespaces 的说法),但我们希望它成为 的典型用例用户程序

$ cat test2.cxx
#include "cryptlib.h"
#include <iostream>

using namespace std;
using namespace CryptoPP;

 // Testing this to select the right byte type
using byte = CryptoPP::byte;

int main(int argc, char* argv[])
{
  CryptoPP::byte block1[16];
  std::byte block2[16];
  byte block3[16];

  return 0;
}

由于 std::byteCryptoPP::byteusing 命名空间,上面的程序具有 byte 的竞争定义...。正如我所说,我知道它还有一些不足之处。

编译程序结果(没有未使用的警告):

$ echo $CXXFLAGS
-DNDEBUG -g2 -O3 -std=c++17 -Wall -Wextra

$ g++ $CXXFLAGS test2.cxx ./libcryptopp.a -o test.exe
test2.cxx: In function ‘int main(int, char**)’:
test2.cxx:12:3: error: reference to ‘byte’ is ambiguous
   byte block3[16];
   ^~~~
test2.cxx:6:28: note: candidates are: using byte = CryptoPP::byte
 using byte = CryptoPP::byte;
                            ^
In file included from stdcpp.h:48:0,
                 from cryptlib.h:97,
                 from test2.cxx:1:
/usr/include/c++/7/cstddef:64:14: note:                 enum class std::byte
   enum class byte : unsigned char {};
              ^~~~

在编译错误中,令我吃惊的是,我们明确地使用 using byte = CryptoPP::byte; 消除了歧义。

我们希望建议在全局命名空间中依赖于 byte 的用户(以及使用 using namespace .... 声明的用户)使用 using byte = CryptoPP::byte; 直到他们有时间更新他们的代码。

我的第一个问题是,为什么编译器声称 byte 在被告知通过 using 使用 CryptoPP::byte 之后是不明确的> 声明?或者这完全是错误的,我们很幸运在编译过程中取得了这么大的进展?

第二个相关问题是,在我们将 byte 迁移到我们的命名空间后,我们是否可以向用户提供任何建议,以便他们现有的代码能够按预期进行编译?还是用户修复代码的唯一选择?

我认为这与问题有关:Context of using declaration and ambiguous declaration . using byte = CryptoPP::byte; 使我感到困惑,因为歧义已被消除。


关于下面的评论和“我认为可以从中吸取关于从一开始就智能使用命名空间的教训”,有一些背景故事。我是戴伟的Crypto++ .它写于 1990 年代初期,使用了无作用域的 byte,因为 C++ 命名空间不可用。命名空间大约在 5 年后出现。

引入 namespace 后,除 byte 外,所有内容都移入了 CryptoPP。根据source code comments , byte 由于“与其他字节类型定义的歧义” 而保留在全局命名空间中。显然,早在 C++17 之前就存在争论。早期的 C++ 编译器可能无法帮助解决这个问题。

事后看来,我们应该计划让某些版本的 C++ 执行此操作(除了糟糕的 using namespace ... 交互)。我们应该已经转移到 CryptoPP::byte,并且可能提供了一个无作用域的 byte 以方便带有适当警告的用户程序。

后见之明总是 20/20。

最佳答案

全局命名空间中的using-directive causes unqualified name lookup to consider all declarations in the nominated namespace as members of the global namespace .它们与全局命名空间的其他成员处于平等地位,因此向全局命名空间添加额外的声明不会解决不合格查找中现有的歧义。

此类声明可以解决限定名称查找歧义(例如,在::byte 中查找byte),因为that lookup only examines namespaces nominated by using-directives if a declaration is not found .这可能是您想到的地方。

关于c++ - 由于使用声明导致字节和歧义符号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45125957/

相关文章:

C++ Windows Server - 如何接受 SSH 连接?

c++ - 为什么我的程序在恰好循环 8192 个元素时很慢?

C++ 为什么我的示例程序不能创建输出文件?

javascript - 在 Javascript 中,何时创建新范围? (使用新功能并在 "with"语句中)只有这两种情况吗?

macros - 检测全局范围的宏

.net Class "is not a member of"Class .. 即使它是?

php - 使用变量作为命名空间

c++ - 搜索可使用自定义 gcc 安装的适用于 OS X 的 C/C++ IDE

swift - 我如何创建一个函数来从 Swift 中的年份返回世纪?

function - XQuery 函数命名空间如何工作?