簡體   English   中英

Functor與模板參數

[英]Functor vs template parameters

使用帶有靜態成員函數的模板參數而不是函子式謂詞時,是否有任何性能優勢?

例如,仿函數風格的排序界面通常是這樣的:

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last ,
    _Pred less_than
    )
{
// actual sorting code here, calling less_than()...
}

你可以做更像這樣的事情,並要求_Pred包含一個靜態成員函數_Pred::less_than

template <typename _Type, typename _Pred>
void sort (
    RandomAccessIterator first,
    RandomAccessIterator last
    )
{
// actual sorting code here, calling _Pred::less_than()...
}

從理論上講,第一種情況可能會在堆上動態創建一個臨時的仿函數對象,而我認為第二種情況在編譯時是完全評估的。 我知道(比方說)gcc和/或msvc擅長優化,但在第一種情況下可以做到相同程度嗎?

此外,我不是要重寫STL排序例程或類似的東西,只是一個更一般的仿函數問題的例子......

正常使用sort不會在堆上放任何東西,原因很簡單,沒有人調用mallocnew 如果你的謂詞導致對mallocnew的調用,無論是在構造函數中還是在比較中,那么你只能責怪自己...

有些堆棧將用於_Pred類型的參數是_Pred (您不能在代碼中調用模板參數_Pred ,因為_Pred是一個保留符號。可以在std::sort的實現中調用它)。 但除了謂詞對象可能具有的任何數據成員所必需的之外,不會有任何相關的工作要做。 如果謂詞沒有數據成員,則優化器將具有字段日,如果它具有數據成員,則靜態成員函數將不支持用戶想要執行的操作。

只要謂詞中的operator()是非虛擬的,編譯器就可以將其內聯到sort的實例化中,如果它可以看到定義並且感覺它是最好的。 當然不能保證什么更快,但是沒有理由認為對靜態成員函數的調用比調用非虛擬非靜態成員函數更快或更慢,也沒有理由更容易或更難排隊。

從理論上講,第一種情況可能會在堆上動態創建一個臨時的仿函數對象,而我認為第二種情況在編譯時是完全評估的。

第一種情況是在堆棧上創建一個臨時的仿函數對象。 您是否擔心Pred::Pred()是否會分配存儲空間? 如果是這樣,您也可以擔心靜態函數是否會出於某種原因在堆上分配存儲。

無論如何,使用這種習慣用法的大多數謂詞仿函數對象都有非常簡單的構造函數,因為它們的唯一目的是調用重載的operator () ,因此編譯器可能會優化對象構造並生成一個簡單的函數調用。

在第一種情況下,您可以創建一個

template<class T>
struct CompareByIntProperties {
    CompareByIntProperties(vector<T::*int> props) : props_(props) {}
    bool less_than(const T& a, const T& b) const {
        for (vector<T::*int>::const_iterator it = props_.begin();
             it != props_.end(); ++it) {
            if (a.(**it) < b.(**it)) return true;
            if (a.(**it) > b.(**it)) return false;
        }
        return false;
    }
    vector<T::*int> props_;
};

這會讓你

vector<Foo::*int> properties;
if (compare_foo) properties.push_back(&Foo::foo);
if (compare_bar) properties.push_back(&Foo::bar);
if (compare_qux) properties.push_back(&Foo::qux);
sort(container.begin(), container.end(), CompareByIntProperties<Foo>(properties));

請原諒任何語法錯誤,這些都沒有經過編譯檢查。 但是你明白了。

在第二種情況下,因為你正在調用靜態方法,所以你沒有自由的統治來自定義這樣的比較器。

我不擔心效率。 如果你沒有訪問任何非靜態的東西,一個好的C ++編譯器將忽略額外的對象創建/破壞,甚至可能內聯比較器。

如果_Pred::less_than不是虛擬的,則兩個解決方案都是相同的,因為編譯器確切知道它是什么函數,並且如果需要可以內聯。

假設我正確理解你的代碼 - 真正的代碼會更清晰。 我假設代碼1執行if (less_than.compare(a, b)) ,而代碼2執行if (_Pred::less_than(a, b))

編輯:我應該提到示例1將按值傳遞對象,因此您將承擔可能涉及的任何成本(如復制構造函數)。

如果我是你,我會不再擔心你是否會通過一種方式而不是另一種方式購買微納秒......並且更擔心不使用保留的名稱!

在擔心像這樣的垃圾之前,你還有很長的路要走。 當你到達那里的時候......希望你已經知道像這樣的廢話是毫無意義的。

雖然,為了使這個“答案”:你的程序也不是很糟糕。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM