Почему в этом конкретном случае не нужно вводить специализацию std :: hash () в пространство имен std? - PullRequest
0 голосов
/ 07 мая 2018

Рассмотрим

using namespace std;

template <typename S, typename T> struct hash<pair<S, T>>
{
    inline size_t operator()(const pair<S, T> &v) const
    {
        return 0;
    }
};

В этом случае и GCC, и Clang компилируют его без предупреждений. Это, однако, противоречит тому, что я прочитал в Интернете, что определение вашей собственной хэш-функции, которая будет использоваться с неупорядоченными типами стандартной библиотеки, требует, чтобы вы поместили определение в пространство имен std.

Интересно, специализируюсь только на pair<int, int>:

template <> struct hash<pair<int, int>>
{
    size_t operator()(const pair<int, int> &v) const
    {
        size_t seed = 0;
        return seed;
    }
};

приводит к ошибке, как мы и ожидаем.

Однако почему первое не приводит к каким-либо предупреждениям компилятора, несмотря на то, что мы не помещаем его в пространство имен std?

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Это относится к Базовая языковая проблема 727 (удаленный текст удаляется после разрешения, курсивный текст добавляется после разрешения, а жирный текст подчеркивается мной):

Явная специализация должна быть объявлена ​​в пространстве имен, включающем специализированный шаблон. Явная специализация, для которой идентификатор объявления или имя-класса-заголовка не определено, должна быть объявлена ​​в ближайшем окружении пространства имен шаблона , или, если пространство имен является встроенным (10.3.1 [namespace.def] ), любое пространство имен из входящего в него набора пространств имен. Такое объявление также может быть определением может быть объявлено в любой области, в которой может быть определен соответствующий первичный шаблон (10.3.1.2 [namespace.memdef], 12.2 [class.mem], 17.6.2 [ temp.mem]) .

Обратите внимание на жирный текст, ближайшее окружающее пространство имен std::hash равно std, и ваша явная специализация не объявлена ​​в std, поэтому она плохо сформирована до разрешения. Частичная специализация не имеет этого ограничения, поэтому ваш первый пример хорошо сформирован еще до разрешения.

Теперь оба ваших примера должны быть правильно сформированы после резолюции. Вы можете видеть, что Clang и MSVC принимают код (обратите внимание, что более старая версия Clang отклоняет его ). Для GCC это уже сообщенная ошибка .

0 голосов
/ 07 мая 2018

Как написано здесь http://umich.edu/~eecs381/handouts/NamespaceGuide.pdf

"Вы указываете компилятору сделать все имена в пространстве имен std частью глобального пространства имен, и, таким образом, на них можно ссылаться безквалификация в остальной части вашего файла исходного кода. Теперь они будут конфликтовать с любыми именами, которые использует ваш собственный код. Это вступает в силу только для текущего модуля компиляции (файла, который компилируется). "

Первый хороший пример, потому что вы импортируете весь контент std (например, шаблон hash) в ваше глобальное пространство имен, так что вы можете написать его специализацию без ошибок.Во втором случае это не работает из-за утечки любого hash шаблона, который должен быть специализированным.

...