Требуются пояснения
От: vdimas Россия  
Дата: 06.12.24 21:56
Оценка: :)
Всем привет, коллега попросил спросить:
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)
{
// строка 321     //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)
Отредактировано 06.12.2024 22:27 vdimas . Предыдущая версия . Еще …
Отредактировано 06.12.2024 22:17 vdimas . Предыдущая версия .
Отредактировано 06.12.2024 22:16 vdimas . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.