2009-12-07 66 views
3

我最近閱讀了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技術只有在您不提供積分轉換運算符時纔有意義。

回答

1
AutoHandleTemplate<ModuleHandlePolicy> hModule(...); 
HMODULE raw_handle = hModule; // if we want to this line works, 
// AutoHandleTemplate<ModuleHandlePolicy> should \ 
// be implicitly converted to it's raw handle type - HMODULE. 

如果一個智能PTR可以隱式轉換到它的原始句柄類型和原始句柄類型可以在一個布爾測試單獨使用,如:

HMODULE the_raw_handle = ...; 
if (the_raw_handle) {} // this line is ok 

對於那些智能的師生比,有不需要(也不應該)將轉換定義爲bool,void *或safe_bool,否則不明確。

operator bool(),void *(),safe_bool()用於smart-ptrs,它不能隱式轉換爲原始句柄或原始句柄不能在布爾上下文中使用。

試試這個代碼:

template<typename HandlePolicy> 
class AutoHandleTemplate 
{ 
public : 
     typedef typename HandlePolicy::handle_t handle_t; 
     typedef AutoHandleTemplate<HandlePolicy> this_type; 
     {details omitted} 

     operator handle_t() const { 
      return m_handle==HandlePolicy::InvalidHandleValue()? 0: m_handle; 
     } 

     // no more conversion functions 

private : 
     handle_t m_handle; 
     {details omitted} 
}; 
+0

d'oh!我從來沒有想過要讓handle_t做這樣的檢查,並像這樣規範化輸出。它可能在這種方法中存在缺陷,因爲零可能是一個有效的句柄值,並且現在處理的轉換可以將一個無效的句柄交給一個可能有效的句柄(即fn(句柄)現在可以交給零處理真正無效的句柄)。這不是世界上最糟糕的,因爲真正的程序需要測試(處理)fn(句柄)還是類似的。 – Mordachai 2009-12-07 22:05:05

+0

我的聲明有問題。運算符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

+0

因此,一種方法可能是使用運算符bool()並注意'hModule << 1','int i = hModule' ... 另一種可能是 AutoHandleTemplate NULL_unacceptable; AutoHandleTemplate INVALID_HANDLE_VALUE_unacceptable; – OwnWaterloo 2009-12-08 01:52:34

0

含糊不清來自兩個可能的轉換運算符;或者:

operator handle_t() const; 
operator unspecified_bool_type() const; 

或:

operator handle_t() const; 
operator bool() const; 

兩者都可以在一個布爾表達式中使用,所以你有歧義。

+0

至少在VC++ 2008中,你可以有一個操作符handle_t()和操作符bool()。如果(句柄)解析爲運算符bool,而fn(句柄)其中fn - > void fn(handle_t)解析爲運算符handle_t。無論這是完全符合標準的行爲,我都不知道。 – Mordachai 2009-12-07 22:06:51

+0

沒錯。在第二種情況下,它並不含糊。不過,我認爲第一個仍然是模棱兩可的。 – MSN 2009-12-07 22:20:24

0

所有成語吸,真的。

最好的解決辦法是:

1)沒有任何的隱式轉換操作符

2)有一個operator!用bool返回類型覆蓋。是的,這意味着某些測試可能需要被編寫爲(!! myObject),但這是一個小的代價。

+0

我很高興看到C++ 0x將有明確的操作符。它似乎是需要由語言本身清理的那些東西之一。它在某些方面更清楚地說明了如果(thing.IsValid())或if(thing.NotNull())等,但是它對通用代碼必須具有特殊知識(或特徵模板)處理「我如何測試T」的邏輯。關於if(p)...有一些非常優雅的地方,其中p是任何指針類型或整型類型。它值得找到一種方法來完成,國際海事組織。 – Mordachai 2009-12-07 22:01:21

相關問題