我最近閱讀了safe bool idiom文章。我曾經見過這種技術使用了幾次,但從來沒有理解爲什麼它的工作原理,或者究竟爲什麼它是必要的(可能像很多,我得到它的要點:簡單地使用operator bool()const允許一些隱式類型轉換shenanigans,但細節對我來說總是有點朦朧)。爲什麼「unspecified_bool」類對內部轉換爲包裝類型失敗?
閱讀了本文,然後在boost的shared_ptr.hpp中查看了它的一些實現,我想我已經掌握了它。但是當我去實施一些我們借用並隨着時間的推移而擴展或開發的類來幫助管理Windows API的工作時,我發現我幼稚的實現無法正常工作(源代碼編譯,但是用法生成沒有找到有效轉換的編譯時錯誤)。
Boost的實現充滿了各種編譯器對C++支持級別的條件。從使用樸素運算符bool()const,到使用指向成員函數的指針,使用指向成員數據的指針。從我所收集的內容來看,指向成員數據的指針對於編譯器來說是最有效的,它們可以處理它所處理的IFF。
我正在使用MS VS 2008(MSVC++ 9)。下面是我嘗試過的幾個實現。它們中的每一個導致模糊的用戶定義轉換或沒有找到運算符。
template<typename HandlePolicy>
class AutoHandleTemplate
{
public :
typedef typename HandlePolicy::handle_t handle_t;
typedef AutoHandleTemplate<HandlePolicy> this_type;
{details omitted}
handle_t get() const { return m_handle; }
operator handle_t() const { return m_handle; }
#if defined(NAIVE)
// The naive implementation does compile (and run) successfully
operator bool() const { return m_handle != HandlePolicy::InvalidHandleValue(); }
bool operator !() const { return m_handle == HandlePolicy::InvalidHandleValue(); }
#elif defined(FUNC_PTR)
// handle intrinsic conversion to testable bool using unspecified_bool technique
typedef handle_t (this_type::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{
return m_handle != HandlePolicy::InvalidHandleValue() ? &this_type::get() : NULL;
}
#elif defined(DATA_PTR)
typedef handle_t this_type::*unspecified_bool_type;
operator unspecified_bool_type() const // never throws
{
return m_handle != HandlePolicy::InvalidHandleValue() ? &this_type::m_handle : NULL;
}
#endif
private :
handle_t m_handle;
{details omitted}
};
而這裏的一個代碼片段,要麼作品(幼稚的做法),或錯誤(或者的unspecified_bool技術,以上):
// hModule is an AutoHandleTemplate<ModuleHandlePolicy>
if (!hModule)
和:
if (hModule)
我已經嘗試啓用運營商!在所有情況下 - 儘管第一種情況起作用,但第二種情況無法編譯(含糊不清)。
這個類似乎對我來說非常像smart_ptr(或auto_ptr)。在這種情況下,它應該支持隱式轉換爲它的底層句柄類型(HMODULE),但是如果(實例)和if(!instance)也應該支持。但是如果我同時定義了operator_t和unspecified_bool技術,我會得到錯誤。
有人可以向我解釋爲什麼是這樣,也許建議一個更好的方法? (或者我應該滿足於樸素的方法,至少在C++ 0x完成並且在我的編譯器中實現了顯式操作符之前)?
編輯:
看來,答案可能是,如果我定義的隱式轉換爲整數,即C++將使用該轉換爲任何如果(例如)類型表達式。至少對於上面的類來說,定義任何其他運算符(運算符bool)的唯一原因是使用隱式積分轉換來顯式重寫其他值(在上述情況下,強制它與INVALID_HANDLE_VALUE進行比較,而不是隱含的NULL)。
使用unspecified_bool技術只有在您不提供積分轉換運算符時纔有意義。
d'oh!我從來沒有想過要讓handle_t做這樣的檢查,並像這樣規範化輸出。它可能在這種方法中存在缺陷,因爲零可能是一個有效的句柄值,並且現在處理的轉換可以將一個無效的句柄交給一個可能有效的句柄(即fn(句柄)現在可以交給零處理真正無效的句柄)。這不是世界上最糟糕的,因爲真正的程序需要測試(處理)fn(句柄)還是類似的。 – Mordachai 2009-12-07 22:05:05
我的聲明有問題。運算符bool()可以避免模糊。如果(處理),處理 - > handle.operator bool(),一次; handle.operator void *(),void * - > bool,兩次,handle-> safe_bool,safe_bool - > bool,兩次。所以handle.operator bool()適用於 隱式轉換和布爾測試。 – OwnWaterloo 2009-12-08 01:39:41
因此,一種方法可能是使用運算符bool()並注意'hModule << 1','int i = hModule' ... 另一種可能是 AutoHandleTemplate NULL_unacceptable; AutoHandleTemplate INVALID_HANDLE_VALUE_unacceptable; –
OwnWaterloo
2009-12-08 01:52:34