2016-06-13 216 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