캐스팅에 일반적인 방법이 있나요 int
에 enum
에가 C++
?
경우 int
의 범위 내에 enum
그것이 반환해야합니다 enum
, 값을 그렇지 않으면 던져 exception
. 일반적으로 작성하는 방법이 있습니까? 둘 이상 enum type
이 지원되어야합니다.
배경 : 외부 열거 형 유형이 있고 소스 코드를 제어 할 수 없습니다 . 이 값을 데이터베이스에 저장하고 검색하고 싶습니다.
답변
분명한 것은 열거 형에 주석을 추가하는 것입니다.
// generic code
#include <algorithm>
template <typename T>
struct enum_traits {};
template<typename T, size_t N>
T *endof(T (&ra)[N]) {
return ra + N;
}
template<typename T, typename ValType>
T check(ValType v) {
typedef enum_traits<T> traits;
const T *first = traits::enumerators;
const T *last = endof(traits::enumerators);
if (traits::sorted) { // probably premature optimization
if (std::binary_search(first, last, v)) return T(v);
} else if (std::find(first, last, v) != last) {
return T(v);
}
throw "exception";
}
// "enhanced" definition of enum
enum e {
x = 1,
y = 4,
z = 10,
};
template<>
struct enum_traits<e> {
static const e enumerators[];
static const bool sorted = true;
};
// must appear in only one TU,
// so if the above is in a header then it will need the array size
const e enum_traits<e>::enumerators[] = {x, y, z};
// usage
int main() {
e good = check<e>(1);
e bad = check<e>(2);
}
배열을 최신 상태로 유지해야하는데 e
, .NET의 작성자가 아닌 경우 이는 성가신 일입니다 e
. Sjoerd가 말했듯이 괜찮은 빌드 시스템으로 자동화 할 수 있습니다.
어쨌든, 당신은 7.2 / 6입니다.
emin이 가장 작은 열거 자이고 emax가 가장 큰 열거 형의 경우 열거 형 값은 bmin에서 bmax 범위의 기본 유형 값이며, 여기서 bmin 및 bmax는 각각 가장 작은 값의 최소값과 최대 값입니다 emin과 emax를 저장할 수있는 비트 필드. 열거 자에 의해 정의되지 않은 값이있는 열거를 정의 할 수 있습니다.
따라서의 작성자 e
가 아닌 경우의 유효한 값이 e
실제로 정의에 표시 된다는 보장이 없을 수도 있습니다 .
답변
추한.
enum MyEnum { one = 1, two = 2 };
MyEnum to_enum(int n)
{
switch( n )
{
case 1 : return one;
case 2 : return two;
}
throw something();
}
이제 진짜 질문입니다. 왜 이것이 필요합니까? 코드는보기 흉하고 작성하기도 쉽지 않으며 (*?) 유지 관리하기도 쉽지 않으며 코드에 통합하기도 쉽지 않습니다. 그것이 틀렸다는 것을 알려주는 코드. 왜 싸울까요?
편집하다:
또는 열거 형이 C ++에서 정수 유형 인 경우 :
enum my_enum_val = static_cast<MyEnum>(my_int_val);
그러나 이것은 위의 것보다 더 추하고 오류가 발생하기 쉽고 원하는대로 던지지 않습니다.
답변
설명했듯이 값이 데이터베이스에있는 경우이 테이블을 읽고 열거 형과 to_enum(int)
함수 를 모두 사용하여 .h 및 .cpp 파일을 만드는 코드 생성기를 작성하는 것이 어떻습니까?
장점 :
to_string(my_enum)
기능 추가가 쉽습니다 .- 유지 보수가 거의 필요하지 않음
- 데이터베이스와 코드가 동기화 됨
답변
C ++에는 내부 검사가 없으며 “도메인 검사”기능이 내장되어 있지 않습니다.
답변
이것에 대해 어떻게 생각하세요?
#include <iostream>
#include <stdexcept>
#include <set>
#include <string>
using namespace std;
template<typename T>
class Enum
{
public:
static void insert(int value)
{
_set.insert(value);
}
static T buildFrom(int value)
{
if (_set.find(value) != _set.end()) {
T retval;
retval.assign(value);
return retval;
}
throw std::runtime_error("unexpected value");
}
operator int() const { return _value; }
private:
void assign(int value)
{
_value = value;
}
int _value;
static std::set<int> _set;
};
template<typename T> std::set<int> Enum<T>::_set;
class Apples: public Enum<Apples> {};
class Oranges: public Enum<Oranges> {};
class Proxy
{
public:
Proxy(int value): _value(value) {}
template<typename T>
operator T()
{
T theEnum;
return theEnum.buildFrom(_value);
}
int _value;
};
Proxy convert(int value)
{
return Proxy(value);
}
int main()
{
Apples::insert(4);
Apples::insert(8);
Apples a = convert(4); // works
std::cout << a << std::endl; // prints 4
try {
Apples b = convert(9); // throws
}
catch (std::exception const& e) {
std::cout << e.what() << std::endl; // prints "unexpected value"
}
try {
Oranges b = convert(4); // also throws
}
catch (std::exception const& e) {
std::cout << e.what() << std::endl; // prints "unexpected value"
}
}
그런 다음 여기 에 게시 한 코드를 사용 하여 값을 전환 할 수 있습니다.
답변
설명하는 것과 같은 것이 존재하는 것을 원하지 않아야합니다. 코드 디자인에 문제가있는 것 같습니다.
또한 열거 형이 범위에 있다고 가정하지만 항상 그런 것은 아닙니다.
enum Flags { one = 1, two = 2, four = 4, eigh = 8, big = 2000000000 };
이것은 범위에 있지 않습니다. 가능하더라도 0에서 2 ^ n까지의 모든 정수를 검사하여 열거 형 값과 일치하는지 확인해야합니까?
답변
열거 형 값을 템플릿 매개 변수로 나열 할 준비가 되었으면 C ++ 11에서 varadic 템플릿을 사용하여이를 수행 할 수 있습니다. 이를 좋은 것으로 볼 수 있으며, 다른 컨텍스트에서 유효한 열거 형 값의 하위 집합을 허용 할 수 있습니다. 외부 소스의 코드를 구문 분석 할 때 종종 유용합니다.
원하는만큼 일반적이지는 않지만 검사 코드 자체는 일반화되어 있으므로 값 집합을 지정하기 만하면됩니다. 이 접근 방식은 간격, 임의의 값 등을 처리합니다.
template<typename EnumType, EnumType... Values> class EnumCheck;
template<typename EnumType> class EnumCheck<EnumType>
{
public:
template<typename IntType>
static bool constexpr is_value(IntType) { return false; }
};
template<typename EnumType, EnumType V, EnumType... Next>
class EnumCheck<EnumType, V, Next...> : private EnumCheck<EnumType, Next...>
{
using super = EnumCheck<EnumType, Next...>;
public:
template<typename IntType>
static bool constexpr is_value(IntType v)
{
return v == static_cast<typename std::underlying_type<EnumType>::type>(V) || super::is_value(v);
}
EnumType convert(IntType v)
{
if (!is_value(v)) throw std::runtime_error("Enum value out of range");
return static_cast<EnumType>(v);
};
enum class Test {
A = 1,
C = 3,
E = 5
};
using TestCheck = EnumCheck<Test, Test::A, Test::C, Test::E>;
void check_value(int v)
{
if (TestCheck::is_value(v))
printf("%d is OK\n", v);
else
printf("%d is not OK\n", v);
}
int main()
{
for (int i = 0; i < 10; ++i)
check_value(i);
}