Информация об изменениях

Сообщение Требуются пояснения от 06.12.2024 21:56

Изменено 06.12.2024 22:16 vdimas

Требуются пояснения
Всем привет, коллега попросил спросить:
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)
Требуются пояснения
Всем привет, коллега попросил спросить:
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)