Немного предыстории:
Я работаю над созданием шаблонного класса, который, как часть специализации шаблона, выводит тип для использования для одного из его членов.Этот элемент данных должен поддерживать потоковую передачу по проводам, и я стараюсь сделать систему максимально гибкой и расширяемой (с целью создания новых вариантов типа путем изменения некоторых высокоуровневых элементов специализации).логика без проникновения в суть кода реализации).Некоторые из существующих применений специализируют этот элемент данных как перечисление, и потоковый код поддерживает преобразование этого значения назад и вперед в 32-разрядное целое число для передачи по проводам.
Поскольку перечисление может быть определено (либо неявно, либо явно) для поддержки другого типа - наиболее опасного в случае 64-битного значения - я хотел бы иметь возможность принудительно установить, что если разрешенный тип является перечислением, его базовый тип должен быть32-разрядное целое число (в общем, мне просто нужно убедиться, что это максимум из 32 битов, но я буду беспокоиться об этой сложности, как только будет работать более простой случай).
Моя попытка решения:
Соединяя некоторые инструменты, предоставляемые type_traits , я придумал следующее:
#include <cstdint>
#include <type_traits>
using TestedType = /* Logic for deducing a type */;
constexpr bool nonEnumOrIntBacked =
!std::is_enum_v<TestedType>
|| std::is_same_v<std::underlying_type_t<TestedType>, std::int32_t>;
static_assert(nonEnumOrIntBacked,
"TestedType is an enum backed by something other than a 32-bit integer");
Однако,когда я пытался скомпилировать это (используя Visual Studio 2017 в последнем обновлении), меня встретил текст ошибки 'TestedType': only enumeration type is allowed as an argument to compiler intrinsic type trait '__underlying_type'
.Видя это, я попробовал альтернативную формулировку, используя std :: disjunction , которая, как я считаю, должна приводить к короткому замыканию при оценке шаблонов, если более раннее условие оценивается как истинное (я пропустил квалификаторы std
для этогонемного более читабельно):
disjunction_v<
negation<is_enum<TestedType>>,
is_same<underlying_type_t<TestedType>, int32_t>
>;
Я также пытался обернуть оскорбительное использование underlying_type_t
внутри enable_if
, основанного на типе enum, но также не смог с этим справиться.
Мой вопрос :
Не являются ли булевы операторы вообще (и std::disjunction
в частности) оценкой шаблонов при коротком замыкании?На странице cppreference для std :: disjunction говорится следующее (выделено мое):
Разъединение имеет короткое замыкание : если естьаргумент типа шаблона Bi с bool (Bi :: value)! = false, тогда создание экземпляра disjunction :: value не требует создания экземпляра Bj :: value для j> i
Читая это, я ожидал бы, что неправильно сформированная природа underlying_type_t<TestedType>
для некоторого не перечислимого типа не будет иметь значения, так как нижестоящие типы не должны рассматриваться, когда что-то вверх по течению было оценено как истинное.1050 * Если мое чтение спецификации неверно по этому вопросу, есть ли другой способ выполнить эту проверку во время компиляции, или мне нужно будет добавить проверку во время выполнения, чтобы применить это?