Почему нельзя объявлять нестатические поля класса constexpr?



В прошлом посте мы задели особенности линковки constexpr сущностей. Однако я не упомянул про нестатические поля класса. И не зря. Потому что нельзя нестатические поля объявлять constexpr. Но почему?



Давайте немного подумаем, что значит constexpr. В глобальном смысле подразумевается, что мы что-то можем вычислить во время компиляции. Для это придуманы константы времени компиляции(constexpr variables) и функции, которые способны делать вычисления в compile-time.



Причем на константы времени компиляции накладываются жесткие ограничения. Их инициализатор должен быть известен во время компилятору на этом самом этапе компиляции(или конструктор класса помечен constexpr). Только тогда можно создать такой объект.



И теперь взглянем на поле класса. Когда оно инициализируется? Правильно, в конструкторе. То есть мы должны начать создавать объект, чтобы инициализировать поле. А создаются объекты во время исполнения. Получается, что наше constexpr поле принадлежит сущности, которой вообще не существует до момента создания экземпляра класса. И как оно тогда может быть константой времени компиляции? Ведь если constexpr variable и создается, то создается только в compile time. А это просто невозможно в таком случае.



На самом деле поле класса может быть constexpr. Но неявно. Когда объект, в котором содержится это поле, сам является constexpr.



Посмотрите на пример на картинке. Там определяется класс с constexpr конструкторами и затем создается constexpr экземпляр этого класса. Чтобы проверить, действительно ли поле a является константой времени компиляции, можно попробовать вызвать шаблонную функцию с интовым шаблонным параметром. Так как шаблонный параметр - часть типа, то его значение должно быть известно на этапе компиляции. Поэтому, если все получится, то это докажет, что a - константа времени компиляции. И действительно, все работает. constexpr объект делает его поля constexpr.



Если мы попробуем разрешить помечать поля класса constexpr, даже одно единственное поле, значит нам нужно гарантировать, чтобы все поля становились constexpr(если это будет делаться неявно, то это явно кринж), и все объекты данного класса могли создаваться только в compile-time. Зачем это нужно? Да вроде как не за чем. В этом очень мало смысла. Можно выделить constexpr интерфейс и жить себе прекрасно в compile-time. И пользоваться полноценным интерфейсом во время выполнения. Слишком много неуверенности в полезности этой фичи. Поэтому и не разрешают так делать.



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



Reach new levels. Stay cool.



#cpp11 #compiler