Size: a a a

2020 September 01

P

PRoSToC0der in pro.cxx
Александр Караев
В чем вообще проблема NTTP параметров?

Рассмотрим простую функцию 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 и прочее - компилятор считает такие типы просто последовательностью более примитивных типов, от которых он умеет считать хеш и сравнивать.
а флоаты кстати как работают в этом контексте? там же вроде какие-то проблемы с ними были?
источник

ПК

Побитый Кирпич... in pro.cxx
Александр Караев
потому что сейчас std::string может выглядеть как const char* ptr; std::size_t cap, len;
какой толк компилятору сравнивать указатели или capacity?
Хочешь сказать, если я сделаю
```
class my_string {
public:
 const char* ptr; std::size_t cap, len;
};
```
То всё норм будет?
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
Компилятор точно так же пройдет по всем мемберам
получится, что
constexpr std::string a = "1";
constexpr std::string b = "1";
static_assert(a == b);
static_assert(&f<a> != &f<b>)
источник

ПК

Побитый Кирпич... in pro.cxx
PRoSToC0der
а флоаты кстати как работают в этом контексте? там же вроде какие-то проблемы с ними были?
не было проблем
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
Хочешь сказать, если я сделаю
```
class my_string {
public:
 const char* ptr; std::size_t cap, len;
};
```
То всё норм будет?
что такое "норм"?
источник

ПК

Побитый Кирпич... in pro.cxx
Александр Караев
что такое "норм"?
Я смогу объекты этого типа передать в шаблон?
источник

АК

Александр Караев... in pro.cxx
PRoSToC0der
а флоаты кстати как работают в этом контексте? там же вроде какие-то проблемы с ними были?
про флоаты не помню, там вроде договорились до чего-то (-0.0 == 0.0 вроде)
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
Я смогу объекты этого типа передать в шаблон?
да
источник

ПК

Побитый Кирпич... in pro.cxx
Тогда  чем это отличается от std::string? Почему один можно, другой нельзя?
источник

ПК

Побитый Кирпич... in pro.cxx
И почему нельзя:
class all_private {
 int i;
 bool b;
};

?
Тут нет никаких проблем в сравнении
источник

N

Neargye in pro.cxx
Александр Караев
В чем вообще проблема NTTP параметров?

Рассмотрим простую функцию 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 и прочее - компилятор считает такие типы просто последовательностью более примитивных типов, от которых он умеет считать хеш и сравнивать.
Меня только концовка смутила
в итоге non public или all public?
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
Тогда  чем это отличается от std::string? Почему один можно, другой нельзя?
смотри, в чем проблема: если у тебя есть приватная часть, то с 99% вероятностью у тебя operator== не сравнивает просто поля друг с другом.
в частности, для строки там сравнение не указателей, а символов в диапазоне [ptr; ptr+size)
источник

АК

Александр Караев... in pro.cxx
Neargye
Меня только концовка смутила
в итоге non public или all public?
опечатка, all public
источник

ПК

Побитый Кирпич... in pro.cxx
Короче ясно, эвристическая связь уровня доступа с логикой сравнения
источник

ПК

Побитый Кирпич... in pro.cxx
короче костыль :)
источник

N

Neargye in pro.cxx
Александр Караев
опечатка, all public
Окс, вопрос снят, а то вроде все логично было а потом нон паблик :D
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
короче костыль :)
не костыль, просто решили перестраховаться и для начала дать минимальные возможности с гарантией, что ничего не сломается
источник

ПК

Побитый Кирпич... in pro.cxx
Александр Караев
не костыль, просто решили перестраховаться и для начала дать минимальные возможности с гарантией, что ничего не сломается
Дак а если я для своей all public структуры перегружу оператор сравнения?
источник

ПК

Побитый Кирпич... in pro.cxx
В этом и костыль, связка должна быть на него а не на доступы, которые косвено свзывают с сравнением
источник

АК

Александр Караев... in pro.cxx
Побитый Кирпич
Дак а если я для своей all public структуры перегружу оператор сравнения?
тогда ты сам себе дурак, но это будут твои рантаймовые проблемы, а не компилятора
источник