Перечисление C ++ с битовой меткой в ​​строку

Я пытаюсь сделать то, что делает Intellisense в Visual Studio, когда вы наводите указатель мыши на переменную побитового перечисления (или как она называется) (во время отладки), беря перечисление и преобразовывая его в строку.

например:

#include <iostream>

enum Color {
White = 0x0000,
Red = 0x0001,
Green = 0x0002,
Blue = 0x0004,
};

int main()
{
Color yellow = Color(Green | Blue);
std::cout << yellow << std::endl;
return 0;
}

Если вы наводите yellow вот увидишь:

введите описание изображения здесь

Поэтому я хочу иметь возможность назвать что-то вроде:

std::cout << BitwiseEnumToString(yellow) << std::endl;

и иметь вывод на печать: Green | Blue,

Я написал следующее, которое пытается обеспечить общий способ печати перечисления:

#include <string>
#include <functional>
#include <sstream>

const char* ColorToString(Color color)
{
switch (color)
{
case White:
return "White";
case Red:
return "Red";
case Green:
return "Green";
case Blue:
return "Blue";
default:
return "Unknown Color";
}
}

template <typename T>
std::string BitwiseEnumToString(T flags, const std::function<const char*(T)>& singleFlagToString)
{
if (flags == 0)
{
return singleFlagToString(flags);
}

int index = flags;
int mask = 1;
bool isFirst = true;
std::ostringstream oss;
while (index)
{
if (index % 2 != 0)
{
if (!isFirst)
{
oss << " | ";
}
oss << singleFlagToString((T)(flags & mask));
isFirst = false;
}

index = index >> 1;
mask = mask << 1;
}
return oss.str();
}

Так что теперь я могу позвонить:

int main()
{
Color yellow = Color(Green | Blue);
std::cout << BitwiseEnumToString<Color>(yellow, ColorToString) << std::endl;
return 0;
}

Я получаю желаемый результат.

Я предполагаю, что я ничего не мог найти об этом, так как я не знаю, как это называется, но в любом случае —

  1. Есть ли что-то в std или boost, что делает это или может быть использовано для обеспечения этого?

  2. Если нет, какой самый эффективный способ сделать это? (или мне хватит)

3

Решение

Вам нужно будет поддерживать список строковых представлений вашего перечисления, будь то в векторе, в жестком коде и т. Д. Это одна из возможных реализаций.

enum Color : char
{
White = 0x00,
Red   = 0x01,
Green = 0x02,
Blue  = 0x04,
//any others
}

std::string EnumToStr(Color color)
{
std::string response;

if(color & Color::White)
response += "White | ";
if(color & Color::Red)
response += "Red | ";
if(color & Color::Green)
response += "Green | ";
if(color & Color::Blue)
response += "Blue | ";
//do this for as many colors as you wish

if(response.empty())
response = "Unknown Color";
else
response.erase(response.end() - 3, response.end());

return response;
}

Затем создайте другую функцию EnumToStr для каждого перечисления, для которого вы хотите сделать это, следуя той же форме

0

Другие решения

РЕДАКТИРОВАТЬ: см. Ниже для общего, template реализация…
Обратите внимание, что это template реализация попирает ПОВСЮДУ ostream«s operator <<() реализации практически для всего! Было бы лучше, если enumЭто были полноценные классы с реализацией базового класса для template, Это общее определение является эквивалентом атомной бомбы в магазине фарфора …


Я написал следующий пример с тестовой функцией. Он использует перегрузки C ++, чтобы вы могли просто cout Color — если вы хотите иметь возможность печатать простое числовое значение, вам нужно будет преобразовать его в int:

#include <iostream>

enum Color {
White = 0x0000,
Red   = 0x0001,
Green = 0x0002,
Blue  = 0x0004,
}; // Color

std::ostream &operator <<(std::ostream &os, Color color) {
static const char *colors[] = { "Red", "Green", "Blue", 0 }; // Synchronise with Color enum!

// For each possible color string...
for (const char * const *ptr = colors;
*ptr != 0;
++ptr) {

// Get whether to print something
bool output = (color & 0x01)!=0;

// Is color bit set?
if (output) {
// Yes! Output that string.
os << *ptr;
} // if

// Next bit in color
color = (Color)(color >> 1);

// All done?
if (color == 0) {
// Yes! Leave
break;
} // if

// No, so show some more...
if (output) {
// If output something, need 'OR'
os << " | ";
} // if
} // for
return os;
} // operator <<(Color)

void PrintColor() {
for (unsigned c = 0; c < 8; ++c) {
Color color = Color(c);
std::cout << color << std::endl;
} // fors
} // PrintColor()

Сначала файл заголовка:

// EnumBitString.h

template <typename ENUM>
const char * const *Strings() {
static const char *strings[] = { "Zero", 0 }; // By default there are no Strings
return strings;
} // Strings<ENUM>()

template <typename ENUM>
std::ostream &operator <<(std::ostream &os, ENUM e) {
const char * const *ptr = Strings<ENUM>();
if (e == 0) {
os.operator <<(*ptr);
return os;
} // if

// For each possible ENUM string...
while (*ptr != 0) {
bool output = (e & 0x01) != 0;

// Is bit set?
if (output) {
// Yes! Output that string.
os.operator <<(*ptr);
} // if

// Next bit in e
e = (ENUM)(e >> 1);

// All done?
if (e == 0) {
// Yes! Leave
break;
} // if

// No, so show some more...
if (output) {
os.operator <<(" | ");
} // if

++ptr;
} // while
return os;
} // operator <<(ENUM)

Далее ваш пример:

// Colors.h

#include "EnumBitString.h"
enum Colors {
White = 0x0000,
Red   = 0x0001,
Green = 0x0002,
Blue  = 0x0004,
NumColors = 4
}; // Colors

template <>
const char * const *Strings<Colors>() {
static const char *strings[] { "White", // Zero case
"Red",
"Green",
"Blue",
0 }; // Don't forget final 0
static_assert((sizeof(strings)/sizeof(strings[0])==NumColors+1, "Colors mismatch!");
return strings;
} // Strings<Colors>()

Затем еще один пример битов в значении:

// Flags.h

#include "EnumBitString.h"
enum Flags {
CF = 0x0001,
//  Res1 = 0x02,
PF = 0x0004,
//  Res2 = 0x08,
AF = 0x0010,
//  Res3 = 0x20,
ZF = 0x0040,
NumFlags = 7
}; // Flags

template <>
const char * const *Strings<Flags>() {
static const char *strings[] =  { "None",
"Carry",
"",
"Parity",
"",
"Arithmetic",
"",
"Zero",
0 }; // Don't forget final 0
static_assert((sizeof(strings)/sizeof(strings[0])==NumFlags+1, "Flags mismatch!");
return strings;
} // Strings<Flags>()

Наконец, тестовая программа:

#include <iostream>

#include "Colors.h"#include "Flags.h"
void TestENUM() {
for (unsigned c = 0; c < 0x0008; ++c) {
Colors color = Colors(c);
std::cout << color << std::endl;
} // for
for (unsigned f = 0; f < 0x0080; ++f) {
Flags flag = Flags(f);
std::cout << flag << std::endl;
} // for
} // TestENUM()

Круто, да?

0

По вопросам рекламы [email protected]