P
Рассмотрим простую функцию
template <T value> void f();
До C++20 в качестве T мог выступать один из небольшого множества типов. Особенность этого множества состояла в том, что можно два объекта типа T
сравнить, убедиться в их эквивалентности. В частности, f<2>
и f<1+1>
оказывались одинаковыми инстанцированиями, так как 2==1+1. А ещё от них от всех можно посчитать хеш по алгоритму, выбранному компилятором.Теперь допустим, что мы хотим сделать
T
= std::string
(допустим также, что строка у нас уже вся обмазана constexpr). Как компилятору проверить, что f<std::string("1")>
и f<std::string("1")>
- это одна и та же функция? Логично, что для этого он должен уметь сравнивать в constexpr
строки. Более того, так как шаблоны кэшируются, то очень хорошо бы ещё уметь и хешировать такие параметры (хеш-таблица быстрее дерева). То есть при инстанцировании очередной f<some_string>
компилятор должен поискать среди уже проинстанцированных f<..>
такую же.Это приводит к необходимости делать подобие constexpr hash + constexpr operator<=>, который должен быть написан автором типа T (std::string или какой-то used-defined). Здесь и засада. Пользователь может написать некорректную реализацию, что приведёт к UB при компиляции, которое невозможно диагностировать. Что просто сломает компилятор.
Поэтому решили сделать требования типа all public и прочее - компилятор считает такие типы просто последовательностью более примитивных типов, от которых он умеет считать хеш и сравнивать.