2016-06-13 188 views
3

我试图通过采取一个枚举并将其转换为字符串,将鼠标悬停在一个按位枚举(或称为)的变量(在调试时)时在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你会看到:

enter image description here

所以我想能够调用是这样的:

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. 有什么性病或升压,做这或可用来提供这个?

  2. 如果不是,做这种事最有效的方法是什么? (或将挖掘suffic)

+0

什么是'singleFlagToString()'?你是不是要调用'ColorToString()'而不是?乍一看,其他一切看起来都不错,但我会使用一个bitshift操作,而不是'index%2'。 –

+0

singleFlagToString是一个'std :: function',它接受enum并将其转换为'const char *'。目的是为了尽可能通用,所以如果你注意到了,我使用第二个参数“ColorToString”调用“BitwiseEnumToString”。 – ZivS

+0

你将如何使用bitshift运算符而不是'index%2'?我可以使用'index&0x1 == 0',但它不是正确的? – ZivS

回答

0

编辑:请参阅下面的一个通用的,template实现... 但是请注意,这template实现践踏遍布ostreamoperator <<() 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() 

酷,是吗?

+0

您未打印“白色”。 为什么这更好? 每次更改枚举时都必须更新字符串数组,并且不会在其上收到编译错误。 此外 - 您的解决方案不是那种通用的... – ZivS

+0

真:我没有一个全零的情况。等一个... –

+0

我现在已经添加了一个零案例。 –

0

你将不得不维护你的枚举的字符串表示列表,无论是在向量中,硬编码等等。这是一个可能的实现。

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

我不会-1你,但这个解决方案根本不是我的问题的答案。它不是通用的,不可扩展的,不是更好的性能,只是简单地展示如何连接字符串...... – ZivS