Сообщение Требуются пояснения от 06.12.2024 21:56
Изменено 06.12.2024 22:17 vdimas
Требуются пояснения
Всем привет, коллега попросил спросить:
https://godbolt.org/z/xhP1b4cn6
строка 321 — работает
если её раскоментировать, и закоментировать следующую — гцц не компилит
После поверхностного вникания я предложил добавить недостающий вариант
И оно ожидаемо сработало.
код подцепляет этот вариант, можно добавить в его тело static_assert
Подцепляет, ИМХО, из этих строчек
https://godbolt.org/z/xhP1b4cn6
сырцы | |
#include <iostream> #include <string> #include <unordered_map> #include <unordered_set> #include <map> using namespace std; namespace umba { namespace enum_helpers { // template<typename Integer, std::enable_if_t<std::is_integral<Integer>::value, bool> = true> // T(Integer) : type(int_t) {} //---------------------------------------------------------------------------- //! Конвертирует enum в подлежащий тип. Версия для 'честных' enum'ов. template< typename EnumType, typename std::enable_if< std::is_enum<EnumType>::value, bool>::type = true > inline typename std::underlying_type< EnumType >::type toUnderlyingType( EnumType flagsVal ) { typedef typename std::underlying_type< EnumType >::type EnumUnderlyingType; return (EnumUnderlyingType)flagsVal; } //---------------------------------------------------------------------------- //! Конвертирует enum в подлежащий тип. Версия для интегральных типов. /*! Часто неохота разбираться, является ли значение int'ом, unsigned'ом, или другим интегральным типом, или же является enum'ом. */ template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value && std::is_integral<EnumType>::value ) , bool>::type = true > inline EnumType toUnderlyingType( EnumType flagsVal ) { return flagsVal; } //---------------------------------------------------------------------------- //! Конвертирует в enum из подлежащего типа. Версия для 'честных' enum'ов. template< typename EnumType, typename std::enable_if< std::is_enum<EnumType>::value, bool >::type = true > inline EnumType fromUnderlyingType( typename std::underlying_type< EnumType >::type flagsVal ) { return (EnumType)flagsVal; } //---------------------------------------------------------------------------- //! Конвертирует в enum из подлежащего типа. Версия для интегральных типов. /*! Часто неохота разбираться, является ли значение int'ом, unsigned'ом, или другим интегральным типом, или же является enum'ом. */ template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value && std::is_integral< EnumType >::value ) , bool>::type = true > inline EnumType fromUnderlyingType( EnumType flagsVal ) { return flagsVal; } //---------------------------------------------------------------------------- template< typename EnumType > inline bool enumLessImpl(EnumType e1, EnumType e2) { typedef typename std::underlying_type< EnumType >::type EnumUnderlyingType; return (EnumUnderlyingType)e1 < (EnumUnderlyingType)e2; } //---------------------------------------------------------------------------- template< typename EnumType > inline bool enumLessEqualImpl(EnumType e1, EnumType e2) { typedef typename std::underlying_type< EnumType >::type EnumUnderlyingType; return (EnumUnderlyingType)e1 <= (EnumUnderlyingType)e2; } //---------------------------------------------------------------------------- template< typename EnumType > inline bool enumGreaterImpl(EnumType e1, EnumType e2) { typedef typename std::underlying_type< EnumType >::type EnumUnderlyingType; return (EnumUnderlyingType)e1 > (EnumUnderlyingType)e2; } //---------------------------------------------------------------------------- template< typename EnumType > inline bool enumGreaterEqualImpl(EnumType e1, EnumType e2) { typedef typename std::underlying_type< EnumType >::type EnumUnderlyingType; return (EnumUnderlyingType)e1 >= (EnumUnderlyingType)e2; } } // namespace enum_helpers } // namespace umba //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #define UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNARY_OPERATOR_IMPL(EnumType, operatorSign) inline EnumType operator operatorSign( EnumType e ) { return umba::enum_helpers::fromUnderlyingType<EnumType>( operatorSign umba::enum_helpers::toUnderlyingType<EnumType>(e) ); } //------------------------------ #define UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType, operatorSign) inline EnumType operator operatorSign( EnumType e1, EnumType e2) { return umba::enum_helpers::fromUnderlyingType<EnumType>( umba::enum_helpers::toUnderlyingType<EnumType>(e1) operatorSign umba::enum_helpers::toUnderlyingType<EnumType>(e2) ); } inline EnumType& operator operatorSign##=( EnumType &e1, EnumType e2) { e1 = e1 operatorSign e2; return e1; } //------------------------------ #define UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType, operatorSign) inline EnumType operator operatorSign( EnumType e1, typename std::underlying_type< EnumType >::type e2) { return umba::enum_helpers::fromUnderlyingType<EnumType>( umba::enum_helpers::toUnderlyingType<EnumType>(e1) operatorSign e2 ); } inline EnumType operator operatorSign( typename std::underlying_type< EnumType >::type e1, EnumType e2) { return umba::enum_helpers::fromUnderlyingType<EnumType>( e1 operatorSign umba::enum_helpers::toUnderlyingType<EnumType>(e2) ); } inline EnumType& operator operatorSign##=( EnumType &e1, typename std::underlying_type< EnumType >::type e2) { e1 = e1 operatorSign e2; return e1; } //------------------------------ #define UMBA_ENUM_CLASS_IMPLEMENT_ENUM_SHIFT_OPERATOR_IMPL(EnumType, operatorSign) inline EnumType operator operatorSign( EnumType e, unsigned sh ) { return umba::enum_helpers::fromUnderlyingType<EnumType>( umba::enum_helpers::toUnderlyingType<EnumType>(e) operatorSign sh ); } inline EnumType& operator operatorSign##=( EnumType &e, unsigned sh ) { e = e operatorSign sh; return e; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- //! Реализует битовые операции для enum-типа #define UMBA_ENUM_CLASS_IMPLEMENT_BIT_OPERATORS( EnumType ) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNARY_OPERATOR_IMPL (EnumType,~) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,|) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,&) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,^) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_SHIFT_OPERATOR_IMPL (EnumType,<<) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_SHIFT_OPERATOR_IMPL (EnumType,>>) //---------------------------------------------------------------------------- //! Реализует битовые операции для enum-типа и подлежащего типа #define UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_BIT_OPERATORS( EnumType ) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,|) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,&) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,^) //---------------------------------------------------------------------------- //! Реализует арифметические операции для enum-типа #define UMBA_ENUM_CLASS_IMPLEMENT_ARITHMETIC_OPERATORS( EnumType ) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNARY_OPERATOR_IMPL (EnumType,+) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNARY_OPERATOR_IMPL (EnumType,-) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,+) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,-) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,*) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,%) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_BINARY_OPERATOR_IMPL(EnumType,/) //---------------------------------------------------------------------------- //! Реализует арифметические операции для enum-типа и подлежащего типа #define UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_ARITHMETIC_OPERATORS( EnumType ) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,+) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,-) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,*) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,/) UMBA_ENUM_CLASS_IMPLEMENT_ENUM_UNDERLYING_TYPE_BINARY_OPERATOR_IMPL(EnumType,%) //---------------------------------------------------------------------------- //! Реализует операции сравнения больше/меньше для enum-типа #define UMBA_ENUM_CLASS_IMPLEMENT_RELATION_OPERATORS( EnumType ) inline bool operator< (EnumType e1, EnumType e2) { return umba::enum_helpers::enumLessImpl (e1, e2); } inline bool operator<=(EnumType e1, EnumType e2) { return umba::enum_helpers::enumLessEqualImpl (e1, e2); } inline bool operator> (EnumType e1, EnumType e2) { return umba::enum_helpers::enumGreaterImpl (e1, e2); } inline bool operator>=(EnumType e1, EnumType e2) { return umba::enum_helpers::enumGreaterEqualImpl(e1, e2); } //---------------------------------------------------------------------------- //! Реализует операции сравнения больше/меньше для enum-типа и подлежащего типа #define UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_RELATION_OPERATORS( EnumType ) inline bool operator< (EnumType e1, typename std::underlying_type< EnumType >::type e2) { return umba::enum_helpers::enumLessImpl (e1, (EnumType)e2); } inline bool operator<=(EnumType e1, typename std::underlying_type< EnumType >::type e2) { return umba::enum_helpers::enumLessEqualImpl (e1, (EnumType)e2); } inline bool operator> (EnumType e1, typename std::underlying_type< EnumType >::type e2) { return umba::enum_helpers::enumGreaterImpl (e1, (EnumType)e2); } inline bool operator>=(EnumType e1, typename std::underlying_type< EnumType >::type e2) { return umba::enum_helpers::enumGreaterEqualImpl(e1, (EnumType)e2); } inline bool operator< (typename std::underlying_type< EnumType >::type e1, EnumType e2) { return umba::enum_helpers::enumLessImpl ((EnumType)e1, e2); } inline bool operator<=(typename std::underlying_type< EnumType >::type e1, EnumType e2) { return umba::enum_helpers::enumLessEqualImpl ((EnumType)e1, e2); } inline bool operator> (typename std::underlying_type< EnumType >::type e1, EnumType e2) { return umba::enum_helpers::enumGreaterImpl ((EnumType)e1, e2); } inline bool operator>=(typename std::underlying_type< EnumType >::type e1, EnumType e2) { return umba::enum_helpers::enumGreaterEqualImpl((EnumType)e1, e2); } //---------------------------------------------------------------------------- #define UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_EQUAL_OPERATORS( EnumType ) template<typename EnumType, typename IntType> inline bool operator==(EnumType e, IntType i) { return umba::enum_helpers::toUnderlyingType(e)==umba::enum_helpers::toUnderlyingType(i); } template<typename EnumType, typename IntType> inline bool operator!=(EnumType e, IntType i) { return umba::enum_helpers::toUnderlyingType(e)!=umba::enum_helpers::toUnderlyingType(i); } inline bool operator!(EnumType e) { return e==0; } /* template<typename EnumType, typename IntType> inline bool operator==(IntType i, EnumType e) { return umba::enum_helpers::toUnderlyingType(e)==umba::enum_helpers::toUnderlyingType(i); } template<typename EnumType, typename IntType> inline bool operator!=(IntType i, EnumType e) { return umba::enum_helpers::toUnderlyingType(e)!=umba::enum_helpers::toUnderlyingType(i); } */ enum EEE { zero, one, two }; enum class CEEE { zero, one, two }; enum class MoveFileFlags { copyAllowed = 1, //!< If the file is to be moved to a different volume, the function simulates the move by using the CopyFile and DeleteFile functions. replaceExisting = 2, //!< If a file named lpNewFileName exists, the function replaces its contents with the contents of the lpExistingFileName file overwrite = 2, //!< Same as replaceExisting writeThrough = 4 //!< The function does not return until the file is actually moved on the disk. Setting this value guarantees that a move performed as a copy and delete operation is flushed to disk before the function returns. The flush occurs at the end of the copy operation. }; UMBA_ENUM_CLASS_IMPLEMENT_BIT_OPERATORS(MoveFileFlags) UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_BIT_OPERATORS(MoveFileFlags) UMBA_ENUM_CLASS_IMPLEMENT_UNDERLYING_TYPE_EQUAL_OPERATORS(MoveFileFlags) inline bool isKindOfName(const std::unordered_set<std::string>& s, const std::string &name) { //return s.find(name)!=s.end(); return true; } int main() { using namespace umba::enum_helpers; cout << "val of EEE::one: " << toUnderlyingType(one) << "\n"; cout << "val of EEE::two: " << toUnderlyingType(two) << "\n"; cout << "val of CEEE::one: " << toUnderlyingType(CEEE::one) << "\n"; cout << "val of CEEE::two: " << toUnderlyingType(CEEE::two) << "\n"; cout << "val of 1: " << toUnderlyingType(1) << "\n"; cout << "val of 2: " << toUnderlyingType(2) << "\n"; cout << "val of copyAllowed : " << toUnderlyingType(MoveFileFlags::copyAllowed) << "\n"; cout << "val of replaceExisting: " << toUnderlyingType(MoveFileFlags::replaceExisting) << "\n"; cout << "MoveFileFlags::replaceExisting==1: " << (MoveFileFlags::replaceExisting==1 ? "true" : "false") << "\n"; MoveFileFlags flags = MoveFileFlags::replaceExisting; } | |
строка 321 — работает
если её раскоментировать, и закоментировать следующую — гцц не компилит
После поверхностного вникания я предложил добавить недостающий вариант
template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value
&& !std::is_integral<EnumType>::value
)
, bool>::type = true
> inline
int toUnderlyingType( EnumType flagsVal )
{
return 0;
}
И оно ожидаемо сработало.
код подцепляет этот вариант, можно добавить в его тело static_assert
template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value
&& !std::is_integral<EnumType>::value
)
, bool>::type bb = false
> inline
int toUnderlyingType( EnumType flagsVal )
{
static_assert(bb);
return 0;
}
Подцепляет, ИМХО, из этих строчек
template<typename EnumType, typename IntType> inline \
bool operator==(EnumType e, IntType i)
Требуются пояснения
Всем привет, коллега попросил спросить:
https://godbolt.org/z/xhP1b4cn6
строка 321 — работает
если её раскоментировать, и закоментировать следующую — гцц не компилит
После поверхностного вникания я предложил добавить недостающий вариант
И оно ожидаемо сработало.
код подцепляет этот вариант, можно добавить в его тело static_assert
Подцепляет, ИМХО, из этих строчек
https://godbolt.org/z/xhP1b4cn6
сырцы | |
| |
строка 321 — работает
если её раскоментировать, и закоментировать следующую — гцц не компилит
После поверхностного вникания я предложил добавить недостающий вариант
template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value
&& !std::is_integral<EnumType>::value
)
, bool>::type = true
> inline
int toUnderlyingType( EnumType flagsVal )
{
return 0;
}
И оно ожидаемо сработало.
код подцепляет этот вариант, можно добавить в его тело static_assert
template< typename EnumType, typename std::enable_if< (!std::is_enum<EnumType>::value
&& !std::is_integral<EnumType>::value
)
, bool>::type bb = false
> inline
int toUnderlyingType( EnumType flagsVal )
{
static_assert(bb);
return 0;
}
Подцепляет, ИМХО, из этих строчек
template<typename EnumType, typename IntType> inline \
bool operator==(EnumType e, IntType i)