열거 형 클래스와 함께 범위 기반 For를 허용합니까?
의 모든 멤버를 반복하는 반복되는 코드 청크가 있습니다 enum class.
for내가 현재 사용 하는 루프는 새로운 range-based for.
새로운 C ++ 11 기능을 활용하여 현재 for루프 의 상세 정보를 줄일 수있는 방법이 있습니까?
개선하고 싶은 현재 코드 :
enum class COLOR
{
Blue,
Red,
Green,
Purple,
First=Blue,
Last=Purple
};
inline COLOR operator++( COLOR& x ) { return x = (COLOR)(((int)(x) + 1)); }
int main(int argc, char** argv)
{
// any way to improve the next line with range-based for?
for( COLOR c=COLOR::First; c!=COLOR::Last; ++c )
{
// do work
}
return 0;
}
즉, 다음과 같이 할 수 있다면 좋을 것입니다.
for( const auto& c : COLOR )
{
// do work
}
열거 형 자체를 반복자로 반복하는 것은 좋지 않으며 deft_code의 답변에서와 같이 실제 반복기를 사용하는 것이 좋습니다. 하지만 이것이 정말로 당신이 원하는 것이라면 :
COLOR operator++(COLOR& x) {
return x = (COLOR)(std::underlying_type<COLOR>::type(x) + 1);
}
COLOR operator*(COLOR c) {
return c;
}
COLOR begin(COLOR r) {
return COLOR::First;
}
COLOR end(COLOR r) {
COLOR l=COLOR::Last;
return ++l;
}
int main() {
//note the parenthesis after COLOR to make an instance
for(const auto& c : COLOR()) {
//do work
}
return 0;
}
여기서 일하기 : http://ideone.com/cyTGD8
반복기 측면에서 가장 쉬운 방법은 다음과 같습니다.
extern const COLOR COLORS[(int)COLOR::Last+1];
const COLOR COLORS[] = {COLOR::Blue, COLOR::Red, COLOR::Green, COLOR::Purple};
int main() {
for(const auto& c : COLORS) {
//do work
}
return 0;
}
여기에서 볼 수 있듯이 : http://ideone.com/9XadVt
(배열에 대한 별도의 선언과 정의로 인해 색상 수가 배열의 요소 수와 일치하지 않으면 컴파일러 오류가 발생합니다. 매우 쉬운 안전성 검사.)
개인적 ++으로 열거 형 연산자를 오버로딩하는 것을 좋아하지 않습니다 . 종종 증가 정말 이해가되지 않습니다 열거 값을. 정말로 원하는 것은 열거 형을 반복하는 방법입니다.
다음은 Enum반복을 지원 하는 일반 클래스입니다. 기능적이지만 불완전합니다. 실제 구현은 생성자에 대한 액세스를 제한하고 모든 반복기 특성을 추가하는 것이 좋습니다.
#include <iostream>
template< typename T >
class Enum
{
public:
class Iterator
{
public:
Iterator( int value ) :
m_value( value )
{ }
T operator*( void ) const
{
return (T)m_value;
}
void operator++( void )
{
++m_value;
}
bool operator!=( Iterator rhs )
{
return m_value != rhs.m_value;
}
private:
int m_value;
};
};
template< typename T >
typename Enum<T>::Iterator begin( Enum<T> )
{
return typename Enum<T>::Iterator( (int)T::First );
}
template< typename T >
typename Enum<T>::Iterator end( Enum<T> )
{
return typename Enum<T>::Iterator( ((int)T::Last) + 1 );
}
enum class Color
{
Red,
Green,
Blue,
First = Red,
Last = Blue
};
int main()
{
for( auto e: Enum<Color>() )
{
std::cout << ((int)e) << std::endl;
}
}
enum class Color {
blue,
red,
green = 5,
purple
};
const std::array<Color,4> all_colors = {Color::blue, Color::red, Color::green, Color::purple};
그때:
for (Color c : all_colors) {
//...
}
여러 번 나는 '없음'값을 원할 때 다음과 같이 사용합니다.
// Color of a piece on a chess board
enum class Color {
white,
black,
none
};
const std::array<Color,3> colors = {Color::white, Color::black};
template <typename CONTAINER>
bool has_item (CONTAINER const & c, typename CONTAINER::const_reference v) {
return std::find(c.begin(), c.end(), v) != c.end();
}
bool is_valid (Color c) {
return has_item(colors, c) || c == Color::none;
}
bool do_it (Color c) {
assert(has_item(colors, c)); // here I want a real color, not none
// ...
}
bool stop_it (Color c) {
assert(is_valid(c)); // but here I just want something valid
// ...
}
boost :: mpl로 영리한 작업을 수행 할 수 있습니다. 대략적인 버전은 다음과 같습니다.
#include <typeinfo>
// ---------------------------------------------------------------------------|
// Boost MPL
// ---------------------------------------------------------------------------|
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/iterator_range.hpp>
#include <boost/mpl/range_c.hpp>
namespace mpl = boost::mpl;
using namespace std;
enum class COLOR
{
Blue,
Red,
Green,
Purple,
Last
};
struct enumValPrinter
{
template< typename T >
void operator() (const T&)
{
cout << "enumValPrinter with: " << typeid( T ).name() << " : "
<< T::value << "\n";
}
};
int main(int, char**)
{
typedef mpl::range_c< int, static_cast<int>( COLOR::Blue ),
static_cast<int>( COLOR::Last ) > Colors;
mpl::for_each< Colors >( enumValPrinter() );
return 0;
}
다음은 테스트 된 예입니다 (GCC 4.6.1).
enum class COLOR
{
Blue,
Red,
Green,
Purple,
First=Blue,
Last=Purple
};
COLOR operator++( COLOR& x ) { return x = (COLOR)(((int)(x) + 1)); }
COLOR operator*(COLOR c) {return c;}
COLOR begin(COLOR r) {return COLOR::First;}
// end iterator needs to return one past the end!
COLOR end(COLOR r) {return COLOR(int(COLOR::Last) + 1);}
int main()
{
for (const auto& color : COLOR()) std::cout << int(color); //0123
return 0;
}
I like the idea a lot and have often wished for it.
The problem I see is what happens when there is a repeated numeric value for an enum item. All the implementations I see above require casts to integral type and ++. Ultimately, I think language support might be required to truly iterate over each item in all cases. It would remove the need to have First, Last or Begin, End although I don't object to this too much. It's like looking for begin() end() for containers.
enum class COLOR
{
Blue,
Red,
Green,
Mauve = 0,
Purple,
Last
};
The numbering starts over at Mauve.
If you're a terrible person you can get this behavior with the preprocessor, something like:
#include <vector>
#include <cstdio>
#define ENUM_NAME COLOR
#define ENUM_VALUES \
ENUM_VALUE(Blue) \
ENUM_VALUE(Red) \
ENUM_VALUE(Green) \
ENUM_VALUE(Purple)
// This block would be a #include "make_iterable_enum.h"
#define ENUM_VALUE(v) v,
enum class ENUM_NAME {ENUM_VALUES};
#undef ENUM_VALUE
#define ENUM_VALUE(v) ENUM_NAME::v,
#define VECTOR_NAME(v) values_ ## v
#define EXPAND_TO_VECTOR_NAME(v) VECTOR_NAME(v)
const std::vector<ENUM_NAME> EXPAND_TO_VECTOR_NAME(ENUM_NAME){ENUM_VALUES};
#undef ENUM_VALUE
#undef ENUM_NAME
#undef ENUM_VALUES
#undef VECTOR_NAME
#undef EXPAND_TO_VECTOR_NAME
// end #included block
int main() {
for (auto v : COLOR_values) {
printf("%d\n", (int)v);
}
}
With minor modifications this could also support eg. ENUM_SETVALUE(Blue, 4) and making a const map from eg. COLOR::Blue to "Blue". And vice-versa.
I wish the standard had just built these features in as options to enum class. None of the workarounds are good.
I'm sure that you can iterate over the members of a C++ initializer_list, so I reckon I've done this in the past:
enum class Color {Red, Green, Blue};
for (const Color c : {Color::Red, Color::Green, Color::Blue})
{
}
Whether there are issues with this, I don't know, but I thought I'd suggest it as it is concise, but not ideal if there are a lot of Colors.
Whether or not you approve of incrementing enums there are times when it is useful. So here's a simple way of doing so:
enum class COLOR
{
Blue,
Red,
Green,
Purple,
First=Blue,
Last=Purple
};
COLOR c;
++( *reinterpret_cast<int*>( &c));
There is no overhead since the compiler will take care of the casting and de-referencing. Add range checking or other capabilities as necessary.
참고URL : https://stackoverflow.com/questions/8498300/allow-for-range-based-for-with-enum-classes
'Nice programing' 카테고리의 다른 글
| -[NSUserDefaults registerDefaults :]의 용도는 무엇입니까? (0) | 2020.11.17 |
|---|---|
| nginx proxy_pass로 요청 URL을 보존하는 방법 (0) | 2020.11.17 |
| Angular JS : 프라 미스에 바인딩하는 방법 (0) | 2020.11.17 |
| Github의 Markdown 파일에 이미지를 표시하는 방법은 무엇입니까? (0) | 2020.11.17 |
| 모바일 장치에서 localhost 웹 사이트보기 (0) | 2020.11.17 |