2016-07-19 45 views
6

我的任務是遷移C++類庫中錯誤處理的概念。先前簡單地返回bool(成功/失敗)的方法將被修改爲返回一個表達機器可讀錯誤代碼和人類可讀解釋(以及其他在此不重要)的對象。C++:我可以讓一個賦值運算符「顯式」嗎

遍及數千行代碼是容易出錯的,因此我嘗試從編譯器獲得此任務的最佳支持。

我的結果類具有 - 其他成員方法中 - 即構建從代碼和代碼中的賦值運算符結果的構造:

class Result 
{ 
    public: 
     typedef unsigned long ResultCode; 
     explicit Result(ResultCode code); // (1) 
     Result& operator=(ResultCode code); // (2) 
}; 

備註:我通常會用一個枚舉類ResultCode這會解決我的問題,但這不是一種選擇。這是因爲主要設計目標是在不同的庫中使用Result,每個庫都應定義自己的一組結果代碼,而不需要一個大的頭文件來定義所有庫的所有可能的結果代碼。實際上,每個類應能夠定義本地結果代碼,以便可以從類頭獲得可能的結果代碼列表。因此代碼不能枚舉在Result中,它們必須由類使用Result類定義。

爲了避免在客戶端代碼

return true; 

聲明隱式轉換,構造已被宣佈明確的。但是在嵌套方法調用中,會發生另一個問題。我說,我有一個方法

bool doSomething() 
{ 
    return true; 
} 

裏面我是用在返回Result對象的函數。我要轉發嵌套調用

Result doSomethingElse 
{ 
    Result result = doSomething(); 
    return result; 
} 

當前實現Result的賦值操作符的結果代碼,這不會給我一個編譯器錯誤 - DoSomething的的布爾返回值()是隱式轉換爲無符號長整數。

正如我在C++文檔中所讀到的,只有構造函數和轉換運算符可能被聲明爲顯式。

我的問題

  1. 爲什麼明確不允許賦值運算符或其他方法?國際海事組織(IMO)會允許任何方法都是明確的,這也是很有道理的。
  2. 是否有其他解決方案來防止賦值運算符的隱式類型轉換?
+1

我知道這是不是你想要的答案,但爲什麼不使用C++中的異常處理機制?不要反對這種語言。與它一起工作。 (加上一個很好的問題,雖然)。 – Bathsheba

+2

難道你不能聲明'template void operator =(T)= delete;'並保留你擁有的那個。它將在正常情況下使用該方法,並嘗試對所有其他類型使用刪除的方法。 – doug65536

+0

我不知道是否有可能甚至是鼓勵,但你可能擴展[系統錯誤類](http://en.cppreference.com/w/cpp/error#System_error)而不是自己完成? –

回答

1

With the current implementation of Result's assignment operator, this is not going to give me a compiler error - the boolean return value of doSomething() is implicitly converted to unsigned long.

關於您發佈的代碼;它的確會導致錯誤error: no viable conversion from 'bool' to 'Result'see here

顯示您在代碼中看到的行爲的最小示例是必需的。實際代碼中可能有其他構造函數或類型轉換,這些轉換對代碼有重大影響。


在明確提出的問題......

Why is explicit not allowed for assignment operators or other methods?

explicit只允許其中的隱式轉換可能發生,即當編譯器將嘗試爲您生成轉換(有一個特殊的案例爲bool)。這種轉換是構造函數和轉換(或鑄造操作符)。

將構造函數或轉換運算符標記爲explicit可以防止編譯器進行轉換,因此,如果需要轉換,則需要對其進行明確說明 - 作爲完成此操作的一般動機,它會使代碼它在做什麼更明確。這是一種折衷,所以在這兩種情況下都應適當使用。一般建議是在懷疑時傾向explicit

例如;

struct Result { 
    Result(long src); // can be marked explicit 
    operator long() const; // can be marked explicit 
}; 

Are there other solutions to prevent implicit type conversion for the assignment operator?

賦值運算符具有特定的Result& operator=(Result&);。在作業本身,沒有轉換。爲防止爲作業隱含創建Result,構造函數需要標記爲explicit

要防止從ResultCode創建Result,您可以不聲明該方法或將其標記爲已刪除;

Result& operator=(ResultCode code) = delete; 
+0

如果不是轉換,那麼Result result = true的幕後會發生什麼;那麼這就給我留下了一個結果代碼1 –

+0

你使用什麼編譯器?這給我一個gcc,clang和msvc的錯誤。 – Niall

+0

@kritzel_sw。你有一個最小的例子顯示編譯(這是不是你所期望的)? – Niall

2

您的問題不在類Result:你明確創建它的一個新的實例,畢竟; explicit不能禁止它。

我不認爲你可以禁止隱含的促銷bool -> long

你可以解決它。一種方法是使ResultCode不是是一個整數類型。那麼,可以有一個明確的構造函數。像

class ResultCode 
{ 
unsigned long m_code; 
public: 
explicit ResultCode(unsigned long code) : m_code(code) {} 
operator unsigned long() { return m_code; } 
}; 

東西可以讓你使用ResultCode任何地方,你可以使用一個unsigned int並創建爲ResultCode res = 5return ResultCode(5)而不是調用一個函數期待一個ResultCode(如Result構造!)有什麼這是不是一個ResultCode已經,如果函數必須返回ReturnCode,也不會做類似return 5

否則,您可以使用模板overloadng爲「抓」什麼不是一個unsigned int並迫使它是一個錯誤

typedef unsigned long ResultCode; 

class Result 
{ 
    ResultCode m_par; 

public: 
    template<typename T> 
    Result(T param) { static_assert(false); } 

    template<> 
    Result(ResultCode par): m_par(par) {} 
}; 

int main() 
{ 
    ResultCode a = 5;  //ok 
    //unsigned long a = 6; //also ok 
    //bool a = true;  //error! 
    //int a = 7;   //also error!! 
    Result b(a); 
}