C++ Bitflaged枚举字符串
我试图通过采取一个枚举并将其转换为字符串,将鼠标悬停在一个按位枚举(或称为)的变量(在调试时)时在Visual Studio中执行什么操作。C++ Bitflaged枚举字符串
例如:
#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;
}
我得到所需的输出。
我猜,我无法找到任何关于它,因为我不知道它是怎么叫呢,但反正 -
有什么性病或升压,做这或可用来提供这个?
如果不是,做这种事最有效的方法是什么? (或将挖掘suffic)
编辑:请参阅下面的一个通用的,template
实现... 但是请注意,这template
实现践踏遍布ostream
的operator <<()
implemantations的几乎一切!如果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()
酷,是吗?
您未打印“白色”。 为什么这更好? 每次更改枚举时都必须更新字符串数组,并且不会在其上收到编译错误。 此外 - 您的解决方案不是那种通用的... – ZivS
真:我没有一个全零的情况。等一个... –
我现在已经添加了一个零案例。 –
你将不得不维护你的枚举的字符串表示列表,无论是在向量中,硬编码等等。这是一个可能的实现。
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功能,以下同形式
我不会-1你,但这个解决方案根本不是我的问题的答案。它不是通用的,不可扩展的,不是更好的性能,只是简单地展示如何连接字符串...... – ZivS
什么是'singleFlagToString()'?你是不是要调用'ColorToString()'而不是?乍一看,其他一切看起来都不错,但我会使用一个bitshift操作,而不是'index%2'。 –
singleFlagToString是一个'std :: function',它接受enum并将其转换为'const char *'。目的是为了尽可能通用,所以如果你注意到了,我使用第二个参数“ColorToString”调用“BitwiseEnumToString”。 – ZivS
你将如何使用bitshift运算符而不是'index%2'?我可以使用'index&0x1 == 0',但它不是正确的? – ZivS