Столкнулся вчера с ситуацией, в которой не компилировался код, казавшийся мне нормальным. Вот минимальный воспроизводимый пример:
#include <cstdint> class vholder_t { public : using underlying_type_t = std::uint_least16_t; class trusted { const underlying_type_t m_value; public: explicit constexpr trusted( underlying_type_t v ) noexcept : m_value{v} {} constexpr auto get() const noexcept { return m_value; }; }; static constexpr trusted max{1000u}; private : underlying_type_t m_value; public : vholder_t( trusted v ) noexcept : m_value{ v.get() } {} }; int main() { using trusted = vholder_t::trusted; constexpr trusted max{1000u}; vholder_t v{ trusted{200u} }; return 0; } |
Ошибка возникала в строчке:
static constexpr trusted max{1000u}; |
Диагностика у разных компиляторов была разной, в основном все говорили о невозможности использовать trusted в constexpr контексте. Кто-то ругался на неопределенные конструкторы в trusted, кто-то на то, что max должен инициализироваться константой.
Собственно, на эту красоту можно полюбоваться на godbolt-е: https://gcc.godbolt.org/z/lP0XlT.Самой полезной оказалась диагностика от GCC-8 (и GCC-9). Оказалось, что компилятор почему-то считает, что в месте объявления max тип trusted еще не определен, поэтому trusted и не может быть задействован в constexpr контексте.
Поэтому был применен следующий workaround:
#include <cstdint> namespace vholder_details { using underlying_type_t = std::uint_least16_t; class trusted { const underlying_type_t m_value; public: explicit constexpr trusted( underlying_type_t v ) noexcept : m_value{v} {} constexpr auto get() const noexcept { return m_value; }; }; } /* namespace vholder_details */ class vholder_t { public : using underlying_type_t = vholder_details::underlying_type_t; using trusted = vholder_details::trusted; static constexpr trusted max{1000u}; private : underlying_type_t m_value; public : vholder_t( trusted v ) noexcept : m_value{ v.get() } {} }; int main() { using trusted = vholder_t::trusted; constexpr trusted max{1000u}; vholder_t v{ trusted{200u} }; return 0; } |
Не припомню, чтобы я где-то раньше о такой особенности современного C++ читал или слышал. Так что решил зафиксировать в склерозник. Вдруг еще для кого-нибудь окажется полезным.
Комментариев нет:
Отправить комментарий