глобальный constexpr типа класса

Я понимаю, что constexpr глобалы типа класса практически непригодны, потому что

  • Такой объект должен быть определен в каждом TU, потому что constexpr не разрешает предварительное объявление объекта.

  • Связь по умолчанию как static приведет к тому, что присвоение имени объекту (использование ODR или нет) во встроенной функции нарушит ODR, потому что соответствующий inline определения будут иметь разное значение.

  • Декларация как extern constexpr одно определение для каждого TU нарушило бы правило ODR, если объект используется ODR, что происходит, когда берется ссылка на него.

    • Ссылка взята для неявного this параметр, даже если он не используется функцией-членом.
    • Очевидно, это происходит, если вы пытаетесь передать объект по ссылке.
    • Также происходит, если вы пытаетесь передать объект по значению, который неявно использует конструктор копирования или перемещения, который по определению передается по ссылке.
    • GCC и Clang жалуются на нарушения ODR (множественные определения), если объект объявлен extern constexpr даже если не используется ODR.

Это все правильно? Есть ли способ иметь constexpr глобальный тип класса без упаковки его в inline функционировать?

15

Решение

Глобальные переменные constexpr могут быть безопасно определены ODR в заголовках, используя немного магии макроса и общеизвестный дополнительный уровень косвенности

#define PP_GLOBAL_CONSTEXPR_VARIABLE(type, var, value)                   \
namespace var##detail {                                                  \
template<class = void>                                                   \
struct wrapper                                                           \
{                                                                        \
static constexpr type var = value;                                  \
};                                                                       \
template<class T>                                                        \
constexpr type wrapper<T>::var;                                          \
}                                                                        \
namespace {                                                              \
auto const& var = var##detail::wrapper<>::var;                           \
}

Макрос предоставляет ссылку в безымянном пространстве имен
к экземпляру объекта в шаблоне класса реализации.

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

Тем не менее, для ссылок не имеет значения, что они имеют другую идентичность;
до тех пор, пока они ссылаются на один и тот же экземпляр объекта в реализации
шаблон класса.

Вы можете обернуть этот макрос в заголовок и безопасно включить его во многие TU.

См. Следующее обсуждение в списке рассылки Boost для получения более подробной информации:
http://lists.boost.org/Archives/boost/2007/06/123380.php

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]