2013-10-17 38 views
0

我有,我想代表作爲字符串一些錯誤代碼:如何從枚舉類型獲取std :: string?

enum class ErrorCode 
{ 
    OK, 
    InvalidInput, 
    BadAlloc, 
    Other 
}; 

我想創建讓代表這些串的錯誤的直觀和簡單的方式。簡單的解決方案是:

std::string const ErrorCode2Str(ErrorCode errorCode) 
{ 
    switch (errorCode) 
    { 
    case OK: 
    return "OK"; 
    case InvalidInput: 
    return "Invalid Input"; 
    case BadAlloc: 
    return "Allocation Error"; 
    case Other: 
    return "Other Error"; 
    default: 
    throw Something; 
    } 
} 

有沒有更好的方法?我可以超載一個ErrorCode串轉換嗎?我可以創建一個ErrorCode::str()函數嗎?有沒有解決這個問題的標準解決方案?

+0

它可以用宏來破解它:http://stackoverflow.com/questions/201593/is-there-a-simple-script-to-convert-c-enum-to-string#201792 – Adam

回答

3

目前沒有完美的解決方案,許多圖書館都在做你正在做的事情。

但是,如果你想要做一個不同的方式,你可以把錯誤變成一個類,像這樣:

#include <iostream> 
#include <string> 
class Error 
{ 
public: 
    Error(int key, std::string message) : key(key), message(message){} 
    int key; 
    std::string message; 
    operator int(){return key;} 
    operator std::string(){ return message; } 
    bool operator==(Error rValue){return this->key == rValue.key; } 
}; 

int main() 
{ 
    Error e(0, "OK"); 

    int errorCode = e; 
    std::string errorMessage = e; 

    std::cout << errorCode << " " << errorMessage; 
} 
+0

這具有非範圍枚舉的大多數問題,例如允許從'Error'到'int'的隱式轉換。它還將錯誤代碼(確保它們不重疊等)分配到客戶端上,而不是像枚舉一樣將其自動化。 –

+0

@JerryCoffin你不能贏得所有的戰爭。例如,用你的代碼,我可以爭辯說這是不安全的,因爲有人可以很容易地添加另一個錯誤的枚舉,並忘記將其添加到類。另一個問題是,每次創建'to_str'浪費內存和CPU時,您都需要分配一張地圖並填充它。 作爲一個班級創建錯誤的美妙之處在於,你可以編輯它你的滿意度。如果你不喜歡上面給出的例子,那麼這是沒有問題的,因爲你可以創建另一個。 – Caesar

+0

你可能無法贏得所有的戰爭,但你似乎幾乎失去了所有的戰爭。在關注打印出錯信息的速度的(不太可能的)事件中,將'strings'映射爲靜態而不會失去其他優勢是很微不足道的 - 但我很難想象它會出現什麼情況是值得的。 –

6

一種可能性是地圖:

class to_str { 
    std::unordered_map<ErrorCode, std::string> strings; 
public: 
    to_str() { 
     strings[ErrorCode::OK] = "Ok"; 
     strings[ErrorCode::InvalidInput] = "Invalid Input"; 
     strings[ErrorCode::BadAlloc] = "Allocation Error"; 
     strings[ErrorCode::Other] = "Other"; 
    } 

    std::string operator()(ErrorCode e) { 
     return strings[e]; 
    } 
}; 

// ... 
auto e = foo(some_input); 
if (e != ErrorCode::OK) 
    std::cerr << to_str()(e); 

這顯然不是一個巨大差異,但我覺得它至少稍微更具可讀性,並認爲它可能在長期內更容易維護一點。

+0

我認爲最好有一個接口,以便我們可以在地圖中添加更多對。我是寫作還是有一些缺點呢? –

+0

@Koushik:不,一般情況下 - 您通常爲枚舉中的所有值定義字符串,並且沒有理由添加其他任何內容。 –

+0

如果未來還有更多錯誤代碼需要添加,那麼重寫這個類會更好嗎? –

1

雖然很多簡單的方法做一個枚舉到字符串或字符串TO-枚舉轉換存在,我想在這裏考慮一種更普遍的方式。

爲什麼C++不允許本地構造它呢?主要有兩個原因:第一個是技術上的:C++沒有任何反射機制:編譯符號簡單地不復存在(並且變成只是數字)。既然他們不存在,你就無法讓他們回來。

第二個更多的是編程問題:編譯器和程序員之間的「共享」。字符串文字在程序和最終用戶之間共享。這可能不是程序員,可能不會說英語(我們不知道他在說什麼)。

解決該問題的一般方法是將其分爲兩部分:一個在流級別,另一個在本地化級別。

當你寫std::cout << 42時會發生什麼?

operator<<(ostream&, int)實現,實際上調用use_facet<num_put<char> >(cout.getloc()).do_put(int),最終使用numpunct方面定義如何處理符號,小數點分隔符和數字組分隔符。

處理枚舉輸出的標準方法是這樣的,通過實現一個ostrea<<enumeral運算符來獲取一個方面並調用它來實際編寫該字符串。

這樣一個方面,他們可以實施多次,並提供給每種支持的語言。

這不容易和直接,但這就是C++ I/O的構想。

一旦你做了所有的事情,獲取字符串的慣用方式是使用一個充滿本地的strngstream,它支持所有枚舉和類所需的構面。

太複雜?也許。但是,如果你認爲這太複雜了,那就停下來教std::cout << "Hello wrld" << std::endl;並寫一個更簡單的「輸出庫」。