2013-01-18 43 views
5

傳遞一個元素到拉姆達的算法裏面,我希望創建一個引用給const接受元素的拉姆達:引用給const

template<typename Iterator> 
void solve_world_hunger(Iterator it) 
{ 
    auto lambda = [](const decltype(*it)& x){ 
     auto y = x; // this should work 
     x = x;  // this should fail 
    }; 
} 

編譯器不喜歡這個代碼:

Error: »const«-qualifier cannot be applied to »int&« (translated manually from German)

然後我意識到decltype(*it)已經是一個參考,當然那些不能進行const。如果我刪除const,代碼會編譯,但我想要x = x失敗。

讓我們相信程序員(這是我)一分鐘,並擺脫const和顯式&,無論如何,由於參考摺疊規則而被丟棄。但是等一等,實際上是decltype(*it)保證是一個參考,還是我應該加上明確的&是安全的?

如果我們不信任的程序員,我能想到的兩種解決方案來解決這個問題:

(const typename std::remove_reference<decltype(*it)>::type& x) 

(const typename std::iterator_traits<Iterator>::value_type& x) 

您可以自己決定哪一個是醜陋的。理想情況下,我想要一個不涉及任何模板元編程的解決方案,因爲我的目標受衆以前從未聽說過。所以:

問題1:decltype(*it)&總是和decltype(*it)一樣嗎?

問題2:如何在沒有模板元編程的情況下通過reference-to-const傳遞元素?

+2

英文錯誤會很好! :) – Pubby

+0

@Pubby我盡我所能,隨時糾正:) – fredoverflow

+0

@sehe問題不是關於頂級常量。 –

回答

4

問題1:否,對InputIterator的要求僅僅是*it可以轉換爲T(表72,在「迭代器要求」中)。

因此,decltype(*it)例如可以是const char&,其迭代器的value_typeint。或者它可能是int。或者double

使用iterator_traits不等於使用decltype,決定你想要什麼。

出於同樣的原因,auto value = *it;確實不是必然給你一個變量與迭代器的值類型。

問題2:可能取決於模板元編程的含義。

如果使用traits類型是TMP,那麼在沒有TMP的情況下沒有辦法指定「對迭代器的值類型的const引用」,因爲iterator_traits是訪問任意迭代器的值類型的唯一方法。

如果你想固定decltype那麼這個怎麼樣?

template<typename Iterator> 
void solve_world_hunger(Iterator it) 
{ 
    const auto ret_type = *it; 
    auto lambda = [](decltype(ret_type)& x){ 
     auto y = x; // this should work 
     x = x;  // this should fail 
    }; 
} 

您可能需要捕捉ret_type爲了使用它的類型,我不能輕易檢查的時刻。

不幸的是,它將迭代器解引用一個額外的時間。你可以寫一些聰明的代碼來避免這種情況,但聰明的代碼最終會成爲替代版本remove_reference,因此TMP。

+0

好的,我會咬緊牙關,然後解釋'iterator_traits'。 – fredoverflow

+0

@FredOverflow:寫一本書/教程? –

+0

不是。如果我寫了一本書,我肯定休息室是第一個知道的;) – fredoverflow