Мы являемся библиотекой C++. В течение многих лет у нас было typedef unsigned char byte; в глобальном пространстве имен. Пользовательские программы и другие библиотеки предоставляли совместимые определения byte, поэтому проблем не возникало.
C++17 добавил std::byte и изменил семантику байта. Теперь нам нужно быть более гигиеничными, избегая загрязнения глобального пространства имен; и нам нужно изолировать себя от std::byte. Наше изменение заключается в перемещении нашего byte в наше пространство имен.
Мы наблюдаем неожиданный сбой, когда проверяем влияние изменений. Приведенная ниже программа не соответствует рекомендациям (согласно Хербу Саттеру на Миграция в пространства имен), но мы ожидаем, что это будет типичный вариант использования для пользовательских программ.
$ 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;
}
Программа выше имеет конкурирующие определения byte из-за std::byte, CryptoPP::byte и using namespace .... Как я уже сказал, я знаю, что это оставляет желать лучшего.
Результат компиляции программы (без неиспользуемых предупреждений):
$ 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 неоднозначен после того, как ему сказали использовать CryptoPP::byte через объявление using? Или это просто неправильно, и нам повезло, что мы продвинулись так далеко во время компиляции?
Второй связанный с этим вопрос: можем ли мы дать какой-либо совет пользователям, чтобы их существующий код компилировался должным образом после того, как мы перенесем byte в наше пространство имен? Или это единственный выбор для пользователей исправить свой код?
Я думаю, что это как-то связано с проблемой: Контекст использования объявления и неоднозначного объявления. using byte = CryptoPP::byte; сбивает меня с толку, так как двусмысленность была устранена.
Что касается комментариев ниже и «Я думаю, что из этого следует извлечь урок о разумном использовании пространств имен с самого начала», есть некоторая предыстория. Это Crypto++ Вэй Дая. Он был написан в начале 1990-х и использовал byte без области видимости, потому что пространства имен C++ были недоступны. Пространства имен появились примерно через 5 лет.
Когда были введены пространства имен, все было перемещено в CryptoPP, кроме byte. Согласно комментариям к исходному коду, byte осталось в глобальном пространстве имен из-за на "неоднозначность с другими определениями типов байтов". По-видимому, разногласия существовали задолго до C++17. Ранние компиляторы C++, вероятно, не помогли решить проблему.
Оглядываясь назад, мы должны были запланировать, чтобы какая-то версия C++ делала это (в дополнение к плохому using namespace ... взаимодействию). Мы уже должны были перейти на CryptoPP::byte и возможно предоставить неограниченный byte для удобства пользовательских программ с соответствующими предупреждениями.
Задним числом всегда 20/20.
using namespace std;нигде. - person Some programmer dude   schedule 16.07.2017usingможно использовать для создания псевдонимов. Их целью не является устранение двусмысленности. - person skypjack   schedule 16.07.2017using byte = CryptoPP::byte;- это просто объявление. Он объявляет псевдоним дляCryptoPP::byteв глобальном пространстве имен, но никоим образом не повышает эту версиюbyteпо сравнению с любой другой версией, присутствующей в глобальном пространстве имен. - person AnT   schedule 16.07.2017