2012-02-05 41 views

回答

17

雖然這通常是通過交換機做,我更喜歡的數組:

#include <iostream> 

namespace foo { 
    enum Colors { BLUE = 0, RED, GREEN, SIZE_OF_ENUM }; 
    static const char* ColorNames[] = { "blue", "red", "green" }; 

    // statically check that the size of ColorNames fits the number of Colors 
    static_assert(sizeof(foo::ColorNames)/sizeof(char*) == foo::SIZE_OF_ENUM 
    , "sizes dont match"); 
} // foo 

int main() 
{ 
    std::cout << foo::ColorNames[foo::BLUE] << std::endl; 
    return 0; 
} 

顯式數組的大小具有生成編譯時 錯誤的利益應在枚舉變化的大小和你忘了加 適當的字符串。

或者,Boost Vault中有Boost.Enum。圖書館 尚未正式發佈,但相當穩定,並提供你想要的 。我不會推薦給新手。

+3

如果您忘記*添加字符串,它不會生成錯誤... – 2012-02-05 18:29:02

+1

@MatthieuM。真正。構建這樣的東西的唯一可靠方法可能是宏。 – pmr 2012-02-05 18:37:13

+0

我很害怕。我一直認爲這也是一種恥辱,我會讚賞編譯器構建函數的一面。我發現的一種方法是使用宏,儘管這或多或少地將函數內聯。另一個是使用測試來確保翻譯適用於以前的類型(至少),然後依靠開發人員*思考* :) – 2012-02-05 19:55:29

8

這本質上是不可能的。

C++ enum只是一組帶編譯時名稱的數字。
在運行時,它們與普通數字無法區分。

您需要編寫一個返回字符串的switch語句。

+1

它是如何工作在C#....反射? – CodingHero 2012-02-05 15:49:15

+0

@CodingQuant:是的。您可以在「Enum」類的源代碼中看到反射。 – SLaks 2012-02-05 19:12:05

0

您可以將這些名稱存儲在一個字符串數組中,其索引值爲enum值。

enum Colours 
{ 
    Red =0, 
    Green=1, 
    Blue=2 
}; 

char* names[3] = {"Red", "Green", "Blue"}; 

然後你就可以打印:"Invalid colour '" + names[colour] + "' selected."

但是,如果你不按順序定義enum值這種方法可能不是非常有用的。在這種情況下,這種方法會浪費記憶。正如亞歷山大•蓋斯勒(Alexander Gessler)所提到的那樣,在enum的值上寫一個switch的函數將會很有用。另一種選擇可能是來自STL的map

1

你必須做手工,即

const char* ToString(Colours co) { 
    switch(co) { 
     case Red: 
      return "Red"; 
     // ... 
    } 
} 

查找表也將是可能的。我還看到有人使用自定義腳本在源代碼之上生成這些東西。

3
enum Color 
{ 
    Red =0, 
    Green=1, 
    Blue=2 
}; 

std::string ColorMap[] = { "Red", "Green","Blue" }; 

使用ColorMap[c]得到字符串表示:

std::string msg = "Invalid colour '" + ColorMap[c] + "' selected."; 

然而,如果枚舉值是不連續的,那麼你可以使用std::map而不是爲:

enum Color 
{ 
    Red = 0x1, 
    Green = 0x2, 
    Blue = 0x4, 
    Black = 0x8, 
}; 

//C++11 only, as it uses std::initializer_list 
std::map<Color, std::string> ColorMap = { 
    {Red, "Red"}, 
    {Green, "Green"}, 
    {Blue, "Blue"}, 
    {Black, "Black"} 
}; 

//same as before! 
std::string msg = "Invalid colour '" + ColorMap[c] + "' selected."; 
+1

在我看來,最好的解決方案,因爲這種方法也可以用於包含空白的枚舉。例如。紅色= 0x01,綠色,藍色= 0x10,黃色。 – Anonymous 2014-06-19 08:17:48

0

As @FlopCoder says:

enum Colours 
{ 
    Red =0, 
    Green=1, 
    Blue=2 
}; 
char* ColourNames[] = { "Red", "Green", "Blue" }; 
int colour = Green; 
printf("Invalid colour '%s' selected.", ColourNames[ colour ]); 

這當然只適用於你的枚舉從0開始並且是連續的。
@ Nawaz的方式是更多雖然C++時尚

+0

看看我的尺寸限制。這使得這個成語更好一些。 – pmr 2012-02-05 15:56:26

+0

的確,我的朋友。 – Petruza 2012-02-05 15:57:50

14

如何一點點魔法與宏:

#include <iostream> 
#include <string> 
#include <vector> 


// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c 
std::vector<std::string> split(const std::string &text, char sep) { 
    std::vector<std::string> tokens; 
    int start = 0, end = 0; 
    while ((end = text.find(sep, start)) != std::string::npos) { 
     tokens.push_back(text.substr(start, end - start)); 
     start = end + 1; 
    } 
    tokens.push_back(text.substr(start)); 
    return tokens; 
} 

#define ENUM(name, ...)\ 
enum name \ 
{\ 
__VA_ARGS__\ 
};\ 
std::vector<std::string> name##Map = split(#__VA_ARGS__, ',');\ 
    std::string toString(const name v) { return name##Map.at(v);} 


ENUM(Color, Red,Green,Blue) 


int main(int c, char**v) 
{ 
    std::cout << toString(Red) << toString(Blue); 
    return 0;//a.exec(); 
} 

是的,我明白,這是醜陋的,你最好不要做做這種事情

+0

醜陋?這是太棒了! – 2012-03-14 11:40:45

+0

我很確定這可以通過C++ 11參數包更乾淨地完成 - 所以在運行時根本不會有任何工作。 – einpoklum 2016-02-04 15:41:03

3

我真的很喜歡的宏觀方法@ Lol4t0 。

我伸出它能夠枚舉從字符串太轉換:

#include <iostream> 
#include <string> 
#include <vector> 

// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c 
std::vector<std::string> split(const std::string &text, char sep) { 
    std::vector<std::string> tokens; 
    int start = 0, end = 0; 
    while ((end = text.find(sep, start)) != std::string::npos) { 
     tokens.push_back(text.substr(start, end - start)); 
     start = end + 1; 
    } 
    tokens.push_back(text.substr(start)); 
    return tokens; 
} 

#define ENUM(name, ...)\ 
    enum name\ 
    {\ 
     __VA_ARGS__\ 
    };\ 
    static const int name##Size = (sizeof((int[]){__VA_ARGS__})/sizeof(int));\ 
    static const vector<string> name##ToStringMap = split(#__VA_ARGS__, ',');\ 
    const string name##ToString(const name value)\ 
    {\ 
     return name##ToStringMap.at(value);\ 
    };\ 
    map<string, name> name##ToFromStringMap(...)\ 
    {\ 
     map<string, name> m;\ 
     name args[name##Size] = { __VA_ARGS__ };\ 
     \ 
     int i;\ 
     for(i = 0; i < name##Size; ++i)\ 
     {\ 
      m[name##ToString(args[i])] = args[i];\ 
     }\ 
     return m;\ 
    };\ 
    static map<string, name> name##FromStringMap = name##ToFromStringMap(__VA_ARGS__);\ 
    const name name##FromString(const string value, const name defaultValue)\ 
    {\ 
     if(name##FromStringMap.count(value) == 0)\ 
     {\ 
      return defaultValue;\ 
     }\ 
     return name##FromStringMap[value];\ 
    }; 

用法:

ENUM(MyEnum, Value1, Value2) 

void main() 
{ 
    string valueName = MyEnumToString(MyEnum::Value2); 
    MyEnum value = MyEnumFromString(valueName, MyEnum::Value1); 
} 

我不是一個C++專家,所以讓我知道你在想什麼或如何做得更好。