gpt4 book ai didi

c++ - 使用编译时常量枚举转换为字符串

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:03:22 30 4
gpt4 key购买 nike

我正在尝试将编译时字符串与枚举值相关联。

这是我第一次尝试解决这个问题:

EnumValue 将在字符串和枚举之间进行编译时关联

template<typename EnumType, int EnumIntValue, const char* EnumStrValue>
class EnumValue
{
public:
static const char* toString()
{
return EnumStrValue;
}

static const int toInt()
{
return EnumIntValue;
}

static EnumType get()
{
return static_cast<EnumType>(EnumIntValue);
}
};

EnumValueHolder 将保存字符串和枚举的实际值。我不喜欢我目前的设计,因为它仍然需要保存一个指向字符串的指针。我更喜欢为此建立编译时关联,但未能提出更优雅的解决方案

template<typename EnumType>
class EnumValueHolder
{
public:
EnumValueHolder()
{}

EnumValueHolder(const EnumType& value, const char* str)
: value(value), str(str)
{}

bool operator==(const EnumValueHolder<EnumType>& rhs) { return value == rhs.value; }
bool operator==(const EnumType& rhs)const { return value == rhs; }

operator EnumType()const
{
return value;
}

const char* toString()const
{
return str;
}

const int toInt()const
{
return static_cast<int>(value);
}

private:
EnumType value;
char const* str;
};

Marcos 可轻松引用枚举类型和枚举值持有者构造

#define ENUM_VALUE_TYPE(enumName, enumValue) \
EnumValue<enumName, (int)enumName::enumValue, str_##enumValue>


#define ENUM_VALUE_MAKE(enumName, enumValue) \
EnumValueHolder<enumName> { \
ENUM_VALUE_TYPE(enumName, enumValue)::get(), \
ENUM_VALUE_TYPE(enumName, enumValue)::toString() }

以下是我的测试用例和使用示例:

const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";


enum class EFruits
{
Apple,
Orange,
Pineapple
};


int main()
{
auto evApple = ENUM_VALUE_MAKE(EFruits, Apple);
std::cout << evApple.toString() << std::endl;

auto evOrange = ENUM_VALUE_MAKE(EFruits, Orange);
std::cout << evOrange.toString() << std::endl;

std::cout << "compare: " << (evApple == evOrange) << std::endl;

evApple = evOrange;
std::cout << evApple.toString() << std::endl;

auto myfruit = ENUM_VALUE_MAKE(EFruits, Pineapple);
std::cout << myfruit.toString() << std::endl;

switch (myfruit)
{
case EFruits::Apple:
std::cout << "Im an apple!" << std::endl;
break;

case EFruits::Orange:
std::cout << "Im an Orange!" << std::endl;
break;

case EFruits::Pineapple:
std::cout << "Im a Pineapple!" << std::endl;
break;

default:break;
}
}

目标之一是删除全局字符串:

const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";

另一种是创建一个将枚举与字符串相关联的宏

//Some crazy define that makes pairs of enum values and strings as
//compile time constants
#define DEFINE_ENUM_STRING(enumValue)\
enumValue, #enumValue

//Ideally, the macro would be used like this. This should be usable in any
//scope (global, namespace, class)
//with any access specifier (private, protected, public)
enum class EFruits
{
DEFINE_ENUM_STRING(Apple),
DEFINE_ENUM_STRING(Orange),
DEFINE_ENUM_STRING(Pineapple)
};

所以有两个主要问题:

1) 当前的设计是否真的能保证将枚举与字符串相关联的编译时间常量?

2) 如何定义一个宏来将枚举值字符串化并使用 1 行在枚举类中声明该值?

编辑:这应该可以在 win64 平台上使用 c++ 11 与 msvs2017 一起工作和编译。

谢谢。

最佳答案

我认为它应该适用于 MSVC2017。它在 constexpr 函数中使用 C++14,但您可以将它们拆分为单个返回语句 constexpr 以与 C++11 兼容(但 MSVC2017 支持 C++14)。

EnumConverter 为每个枚举条目存储 char*、枚举和字符串哈希值。对于每个枚举,您必须专门化 EnumConverter::StrEnumContainer。可以使用您指定的类似宏生成枚举字符串对。

#include <tuple>
#include <array>
#include <stdexcept>

using namespace std;

enum ELogLevel {
Info,
Warn,
Debug,
Error,
Critical
};

static constexpr size_t constexprStringHash( char const* const str ) noexcept
{
return (
( *str != 0 ) ?
( static_cast< size_t >( *str ) + 33 * constexprStringHash( str + 1 ) ) :
5381
);
}

class EnumConverter final
{
public:

EnumConverter() = delete;
EnumConverter( const EnumConverter& ) = delete;
EnumConverter( EnumConverter&& ) = delete;
EnumConverter& operator =( const EnumConverter& ) = delete;
EnumConverter& operator =( EnumConverter&& ) = delete;

template< typename ENUM_T >
static constexpr const char* toStr( const ENUM_T value )
{
const auto& strEnumArray{ StrEnumContainer< ENUM_T >::StrEnumPairs };
const char* result{ nullptr };
for( size_t index{ 0 }; index < strEnumArray.size(); ++index ) {
if( std::get< 1 >( strEnumArray[ index ] ) == value ) {
result = std::get< 0 >( strEnumArray[ index ] );
break;
}
}
return ( ( result == nullptr ) ? throw std::logic_error{ "Enum toStrBase conversion failed" } : result );
}

template< typename ENUM_T >
static constexpr ENUM_T fromStr( const char* const str )
{
const auto& strEnumArray{ StrEnumContainer< ENUM_T >::StrEnumPairs };
const size_t hash{ constexprStringHash( str ) };
const ENUM_T* result{ nullptr };
for( size_t index{ 0 }; index < strEnumArray.size(); ++index ) {
if( std::get< 2 >( strEnumArray[ index ] ) == hash ) {
result = &( std::get< 1 >( strEnumArray[ index ] ) );
}
}
return ( ( result == nullptr ) ? throw std::logic_error{ "Enum toStrBase conversion failed" } : *result );
}

private:
template< typename ENUM_T, size_t LEN >
using ARRAY_T = std::array< std::tuple< const char* const, const ENUM_T, const size_t >, LEN >;

template< typename ENUM_T >
static constexpr std::tuple< const char* const, ENUM_T, size_t > getTuple( const char* const str, const ENUM_T type ) noexcept
{
return std::tuple< const char* const, ENUM_T, size_t >{ str, type, constexprStringHash( str ) };
}

template< typename ENUM_T >
struct StrEnumContainer
{
};

template< typename ENUM_T >
friend struct StrEnumContainer;
};

template<>
struct EnumConverter::StrEnumContainer< ELogLevel >
{
using ENUM_T = ELogLevel;

static constexpr EnumConverter::ARRAY_T< ENUM_T, 5 > StrEnumPairs{ {
{ getTuple( "Info", ENUM_T::Info ) },
{ getTuple( "Warn", ENUM_T::Warn ) },
{ getTuple( "Debug", ENUM_T::Debug ) },
{ getTuple( "Error", ENUM_T::Error ) },
{ getTuple( "Critical", ENUM_T::Critical ) },
} };
};

int main()
{
//static_assert( EnumConverter::fromStr< ELogLevel >( "Info" ) == EnumConverter::fromStr< ELogLevel >( EnumConverter::toStr( Error ) ), "Error" ); // Error
static_assert(
EnumConverter::toStr( Warn )[ 0 ] == 'W' &&
EnumConverter::toStr( Warn )[ 1 ] == 'a' &&
EnumConverter::toStr( Warn )[ 2 ] == 'r' &&
EnumConverter::toStr( Warn )[ 3 ] == 'n',
"Error"
);
static_assert( EnumConverter::fromStr< ELogLevel >( "Info" ) == EnumConverter::fromStr< ELogLevel >( EnumConverter::toStr( Info ) ), "Error" );
}

关于c++ - 使用编译时常量枚举转换为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55448429/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com