Являются ли переменные-члены статической константы идентичными параметрам шаблона, не относящимся к типу?

#c #language-lawyer #c 20

Вопрос:

У меня есть шаблон класса для N-мерного массива:

 templatelt;typename T, std::size_t... Shapegt; class ndarray { ... };  

Одним из следствий такого дизайна шаблона является наличие дополнительного «неявного» параметра шаблона , если хотите: std::size_t Size , произведение всех аргументов в Shape . Я использовал сложенное выражение C 17 ( (1 * ... * Shape) ), которое я обычно использовал Size бы, если бы оно не зависело от Shape , но мне интересно, приведет ли добавление следующего «псевдонима» к каким-либо незначительным различиям в скомпилированной сборке:

 templatelt;typename T, std::size_t... Shapegt; class ndarray {  static constinit std::size_t Size = (1 * ... * Shape);  ... };  

Интересно, что стандарт ISO C 20 не указывает, подразумевает ли это или нет constinit inline , как это делается для constexpr и consteval . Я думаю , что семантика constinit (особенно в отношении constexpr переменных) действительно имеет смысл только в том случае, если переменная также inline была, но ее отсутствие в стандарте заставляет меня с осторожностью относиться к этому выводу.

Комментарии:

1. Почему бы вам вместо этого сделать его constinit переменной constexpr ? Планируете ли вы изменить его позже?

2. @NicolBolas Вау! Ваш комментарий заставил меня взглянуть constinit еще раз, и сначала я совершенно неправильно его понял.

Ответ №1:

constinit имеет ровно и только одну семантику: выражение, используемое для инициализации переменной, должно быть постоянным выражением.

Это оно. Это все, что он делает: он вызывает ошибку компиляции, если инициализирующее выражение не является допустимым постоянным выражением. Во всех других отношениях такая переменная идентична отсутствию constinit там. Действительно, в ранних версиях предложения константа была атрибутом, а не ключевым словом, поскольку на самом деле она ничего не делала. Это только дало ошибку компиляции для недопустимой инициализации переменной.

В этом случае нет причин не делать переменную constexpr . Вы явно не собираетесь изменять переменную, поэтому нет смысла изменять переменную.

Ответ №2:

Нет, это совсем не одно и то же, потому constinit что не делает переменную переменной const . Таким образом, инициализация Size даже не является допустимой. Письмо constinit const в основном эквивалентно письму constexpr , которое семантически эквивалентно постоянному складчатому выражению. Нет никакой гарантии, что какой-либо компилятор обрабатывает их одинаково, но в большинстве случаев с постоянным выражением не так много места для вариаций.

constinit также не подразумевает inline : дело не в том, что стандарт «не указывает», просто нечего сказать. Поскольку нет смысла указывать constinit и constexpr на одну и ту же переменную, неясно, какую семантику вы ожидаете в этой области.