Будет ли специализация шаблонов функций в std для программных типов больше не разрешена в С++ 20?

Цитата из cppreference.com:

Добавление специализированных шаблонов

Разрешено добавлять специализированные шаблоны для любой стандартной библиотеки | class (с С++ 20) | шаблон в пространство имен std, только если декларация зависит, по крайней мере, от одного определенного типа программы, и специализация удовлетворяет всем требованиям для исходного шаблона, за исключением случаев, когда такие специализации запрещены.

Означает ли это, что начиная с С++ 20 добавление специализаций шаблонов функций в пространство имен std для пользовательских типов больше не будет разрешено? Если это так, это означает, что многие фрагменты существующего кода могут сломаться, не так ли? (Мне кажется, что это "радикальное" изменение). Кроме того, он вводит в такие коды неопределенное поведение, которое не будет приводить к ошибкам компиляции (мы надеемся, что будут предупреждения).

Ответ 1

В настоящее время он определенно выглядит именно так. Ранее [namespace.std] содержалось

Программа может добавить специализацию шаблона для любого стандартного шаблона библиотеки к пространству имен std только в том случае, если объявление зависит от определенного пользователем типа, а специализация соответствует требованиям стандартной библиотеки для исходного шаблона и явно не запрещена.

Хотя текущий проект утверждает

Если это явно запрещено, программа может добавить специализацию шаблона для любого стандартного шаблона класса библиотеки в пространство имен std при условии, что (a) добавленное объявление зависит, по меньшей мере, от одного определенного типа программы и (b) специализация соответствует требованиям стандартной библиотеки для оригинальный шаблон.

акцент мой

И это похоже на бумагу Thou Shott Not Specialized std Function Templates! Вальтер Э. Браун отвечает за это. В нем он подробно объясняет, почему это должно быть изменено, например:

  • Herb Sutter: "специализации не участвуют в перегрузке. [...] Если вы хотите настроить шаблон базы функций и хотите, чтобы эта настройка принимала участие в разрешении перегрузки (или, чтобы всегда использоваться в случае точного соответствия), сделайте это простая старая функция, а не специализация. И если вы обеспечиваете перегрузки, избегайте также специализации ".
  • Дэвид Абрахамс: "Неправильно использовать специализированную функцию шаблона [потому что] он плохо взаимодействует с перегрузками. [...] Например, если вы специализируетесь на регулярной std::swap для std::vector<mytype>&, ваш специализация не будет выбрана по сравнению с стандартным вектором специфического swap, поскольку специализации arent учитываются при разрешении перегрузки ".
  • Говард Хиннант: "Этот вопрос давно разрешен... Не обращайте внимания на мнение Дэйвса/ответ в этой области на свой страх и риск".
  • Эрик Ниблер: "[из-за] решительно неудобный способ C++ разрешает вызовы функций в шаблонах..., [w] e делает неквалифицированный вызов для swap, чтобы найти перегрузку, которая может быть определена в [...] связанных с именами [...], и мы using std::swap так что, во избежание такой перегрузки, мы находим версию по умолчанию, определенную в пространстве имен std. "
  • Стандарт кодирования с высокой степенью целостности C++: "Разрешение перегрузки не учитывает явные специализации шаблонов функций. Только после выбора разрешения перегрузки шаблон функции будет рассматривать любые явные специализации".

Ответ 2

Не совсем такой радикал. Это изменение основано на этой статье от Уолтера Э. Брауна. Документ довольно глубоко обоснован, но в конечном итоге это сводится к следующему:

  1. Специализация шаблонов функций довольно плохая как точка настройки. Перегрузка и ADL намного лучше в этом отношении. В документе также есть другие пункты настройки.
  2. Стандартная библиотека не слишком полагается на эту плохую настройку.
  3. Внесение изменений в формулировку фактически позволяет добавлять целые объявления в пространство имен std (а не только специализации), где это явно разрешено. Итак, теперь есть лучшие точки настройки.

Учитывая # 1 и # 2, это довольно маловероятно, что существующий код сломается. Или, по крайней мере, недостаточно, чтобы это было серьезной проблемой. Код, который использовал auto и register также "сломался" в прошлом, но эта незначительная сумма кода C++ не остановила прогресс.