2014-01-20 88 views
8

我有一個模板函數接收函數對象。有時函數對象是無狀態結構,但有時它們是大型有狀態對象。函數對象的狀態在這個函數中不會被改變,只會被檢查。我也非常熱衷於編寫能夠儘可能優化編譯器的代碼。在選擇參數類型時我應該考慮什麼?函數對象的正確參數類型是什麼?

功能是這種類型的:

template<typename funcT> 
auto make_particle(funcT fun) { 
    Particle<typename funcT::result_type> particle; 
    particle = fun(); 
    return particle; 
} 

參數類型也許應該funcT const & fun,這樣大的物體不會被複制,但爲什麼大多數人使用的調用 - 值函數的對象?我是否使用const引用丟失了某些東西?還是應該使用左值參考?請注意,C++ 1y可以,上面的代碼示例只是一個示例。

回答

5

參數類型也許應該是本功能常量&樂趣,這樣的 大的對象不會被複制,

這不是由算法標準庫所持的看法。在那裏,可調用的對象是有價值的。這是由可回收對象的作者來確保其合理的便宜的複製。例如,如果它需要訪問很大的東西,那麼你可以讓仿函數的用戶提供一個引用並將其存儲在仿函數中 - 複製引用很便宜。

現在,它可能是你想做的事情不同於標準庫,因爲你期望粒子製作功能非常難以使複製或移動便宜。但是C++程序員熟悉被複制的仿函數,所以如果你做標準庫所做的事情,那麼通常你並沒有比現在更糟。複製仿函數不是一個問題,除非你把它做成一個:-)

7

有幾種使用情況,這都應該是可用的:

  • 函子沒有狀態並作爲一個臨時的:make_particle(MyFun())

  • 函子有它需要一個狀態後回收:YourFun f; make_particle(f);

不能解決與一個單一的參考類型參數兩種情況:第一種當R要求const左值引用或右值引用,禁止第二次使用,第二種情況要求左值引用,禁止第一次使用。

在這種情況下一個常見的成語是接受值的函子,並末返回它

template <typename Iter, typename F> 
F map(Iter first, Iter last, F f) 
{ 
    // ... f(*first) ... 
    return f; 
} 

這可能不完全適用於你的情況下,雖然,但它是一個想法。例如,您可以返回std::pair<ParticleType, F>。無論如何,你都需要你的函數類型是可複製的,但這是一個合理的要求。

一種替代,有益指出的@Xeo,並且可用於功能模板只,是普遍的參考取函子的說法,這將在兩種情況下工作:

template <typename Iter, typename F> 
void map(Iter first, Iter last, F && f) 
{ 
    // ... use f(*first) ... 
} 

注意,在這種情況下,我們做而不是使用std::forward,因爲我們使用f作爲真正的參考,而不僅僅是通過其他地方。特別是,如果我們仍然打算使用它,我們不允許從f移動。

+1

你可以很容易地解決這兩種情況與一個單一的參考參數 - T &&,又名通用引用。 – Xeo

+0

@Xeo:最初我想提供一個*函數*,而不是模板,所以我一直在尋找一個解決方案。你當然是對的,因爲我們已經有了模板,所以我們不妨使用它們。 –

相關問題