tgoop.com/cxx95/141
Last Update:
#jostik #compiler
Обзор жостиков C++ 0b11
)
На этот раз будет аж семь жостиков - три про DIY в Clang, одно про устройство Wireshark, одно с видео, и пара про идиомы C++
У enum'ов в C++ нет наследования. Но это могло бы быть полезным в редких случаях, когда есть общий enum для всех кейсов, но в каких-то окружениях есть мелкие различия, которыми не хочется засорять общее место.
Пусть программа работает с большими ресторанами, куда отправляем запросы на доставку. С нашей стороны можно запросить новую доставку или отмену доставки (статус становится Adding
/Cancelling
и ждется ответ от сервера), после ответов от сервера статус становится Added
/Cancelled
/Delivered
.
Большинство ресторанов не имеет возможности изменить адрес доставки (только отменять и создавать новую), но пусть какое-нибудь "Кафе Пушкинъ"
enum class DeliveryStatus : uint8_t {
Adding,
Added,
Cancelling,
Cancelled,
Delivered,
};
enum class CafePushkinDeliveryStatus : DeliveryStatus {
Moving,
};
(Планируется, что при изменении заказа статус меняется
Added -> Moving -> Added
)Я попробовал придумать дизайн для наследования
enum class First : short {
None, /* = 0 */
MovedPermanently = 301,
Found, /* = 302 */
SeeOther, /* = 303 */
};
enum class Second : First {
NotModified, /* = 304 */
UseProxy, /* = 305 */
BadRequest = 400,
Unauthorized, /* = 401 */
};
enum class Third : Second {
PaymentRequired, /* = 402 */
Forbidden, /* = 403 */
InternalServerError = 500,
};
static_assert(sizeof(First) == 2);
static_assert(sizeof(Second) == 2);
static_assert(sizeof(Third) == 2);
static_assert(std::is_same_v<std::underlying_type_t<First>, short>);
static_assert(std::is_same_v<std::underlying_type_t<Second>, First>);
static_assert(std::is_same_v<std::underlying_type_t<Third>, Second>);
inline constexpr Third kFound = First::Found;
inline constexpr Third kFound = Third::Found;
То есть lookup по
Third::Found
находит enum constant First::Found
(имеет тип First
), потом на нем делается implicit cast к типу Third
Сделал proof of concept в Clang - ссылка на дифф
(Это базовый вариант - нет тестов, не супер красивый код, не рассмотрена возможность множественного наследования, и так далее...)
Код компилятора жесткий, есть много хаков чтобы например различать
a ? new enum E : int{}
от foo(a, enum E : int{})
.Также под флагами поддерживается нестандартный синтаксис, например можно писать
enum E : int *p;
что равносильно enum E : int; E *p;
(прикол от microsoft)ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ