2013-06-03 24 views
2

我有一個容器類,在各種格式的像素上運行。有些格式只是將像素存儲在內存中,因此容器的參考類型是像素&。其他格式將像素存儲在打包字節中。沒有什麼可以返回引用,所以在這種情況下引用類型是代理類型。我所有的代理類型都有一個名爲value_type的嵌入式typedef,它是基礎像素的類型。在這種情況下,有什麼方法可以提高模板參數推導嗎?

我在嘗試編寫對像素進行操作的函子時遇到了問題。舉例來說,我希望能夠寫類似:

std::for_each(container.begin(), container.end(), Incrementer()); 

我已經能夠得到這個工作兩種不同的方式,但我不喜歡任何一方的,所以我很想知道這是否可以改善。

第一種方法是:

struct Incrementer { 

    template <typename Pixel> 
    void operator()(Pixel& p) { 
    p = p + 1; 
    } 

    template <typename Proxy> 
    void operator()(Proxy p, typename Proxy::value_type* dummy=0) { 
    p = p + 1; 
    } 
}; 

的基本想法是,我有兩個重載,一個是其中容器返回引用像素的情況下,一個地方返回代理。我需要第二個重載的虛擬參數,以便參考案例是明確的。問題在於我使用的每個仿函數都需要這兩個重載(包括啞參),所以我認爲這個接口相當難看。

也許我可以編寫一些模板魔法來清理參數類型,但我一直遇到編譯器永遠不會推斷引用參數的問題,所以我需要提供一個非常量引用的重載。另一方面,代理是臨時的,所以它不能被非const引用傳遞。這讓我陷入了兩次重載。

有什麼我失蹤了嗎?

回退的解決辦法是這樣的:

template < typename PixelReference > 
    struct Incrementer { 

    void operator()(PixelReference p) { 
     p = p + 1; 
    } 
    }; 

    std::for_each(container.begin(), container.end(),  
       Incrementer< pixel_traits<Pixel,Format>::reference >()); 

(假設我有一個像素的traits類)。現在我必須在創建仿函數時指定引用類型,這通常很麻煩。

有沒有什麼方法可以改進這些替代方案?我正在編寫這個容器作爲一個庫,所以我試圖儘可能簡單地編寫和使用函子。

謝謝。

回答

2

使用std::for_each()可能會阻止您。如果您使用std::transform()而不是?它甚至還支持同就地修改:

transform(container.begin(), container.end(), container.begin(), Incrementer()); 

然後Incrementer::operator()只需要對於傳值實現的,因爲它將不再明確修改像素的地方。當然,你需要支持爲你的迭代器分配一個代理值,但也許這並不困難。

+0

我絕對可以做到這一點。爲迭代器分配代理可以正常工作,所以我認爲這是一個很好的技術解決方案。我唯一的擔心是我正在將容器編寫成一個庫,並且我認爲用戶希望for_each能夠工作,而不必向後彎曲太遠而無法容納代理。謝謝。 – user1806566

0

我認爲有幾種方法可以解決您的問題。

1。在你的例子都operator() S皆相等,那麼你已經在使用編譯時多態性和你的問題是operator()

多個定義編輯

的代碼應該是這樣的:

struct Incrementer { 
    template <typename Pixel_or_Proxy> 
    void operator()(Pixel_or_Proxy& p) { 
    p = p + 1; 
    } 
}; 

2.使用boost enable_if & disable_if並在boost.mpl BOOST_MPL_HAS_XXX_TRAIT_DEF的幫助下檢查value_type

3.in case you [R代理是你可以爲它創建一個更好的過載的模板:

template<class T> 
void operator()(T t) { 
    // normal operation 
} 

template<class T> 
void operator()(Proxy<T> t) { 
    // proxy operation 
} 

編輯

選項2:作爲方法的機構是平等的,你只需要編寫一個模板方法。類型名稱PixelProxy只是對編譯器沒有任何語義含義的名稱,僅限於用戶。編譯器只是用給定的類型實例化模板方法。如果你有不同的方法,你需要通過重載選擇其中的一個。這可以通過enable_if和朋友或通過額外的call with help of type traits完成。

+0

是的,方法的主體是一樣的。我不能想出一個適用於兩者的方法聲明,所以我最終實現了兩次。關於#2,是不是我的虛擬參數與enable_if會做同樣的事情?由於函數對象將不得不由用戶編寫,我寧願不將它們暴露給它們可能不熟悉的boost庫。對於#3,它不是一個模板,但我可以編寫一個模板包裝來使這個語法工作 - 這將使dummy_arg/enable_if事情變得模糊。謝謝。 – user1806566

+0

這兩個重載的原因是一個(非代理)必須是非const引用,但代理不能是非const引用,因爲代理是臨時的。 – user1806566

相關問題