2017-07-14 30 views
1

我有調用函數的一個問題:C++隱性/明確的模板法專業化問題

namespace Sort { 

    enum Type { 
     insertion, selection, merge 
    }; 

    template <class Elem = int, class Container = std::vector<Elem>> 
    void sort(std::shared_ptr<Container> vectorPointer, 
       std::function<bool(Elem, Elem)> comparator = std::less<Elem>(), 
       Type type = selection) { 

     switch (type) { 
      case insertion: 
       insertionSort(vectorPointer, comparator); 
      case selection: 
       selectionSort(vectorPointer, comparator); 
      case merge: 
       mergeSort(vectorPointer, comparator); 
     } 
    } 
} 

當我把它作爲這樣:但是如果我開始更換

std::shared_ptr<std::vector<int>> intVector; 

Sort::sort(intVector); 

一切都OK,默認參數:

Sort::sort(intVector, std::less<int>(), merge); 

我得到一個錯誤信息:Candidate template ignored: could not match 'function' against 'less'

更新:

我終於使它的工作 - 明確專門的函數調用似乎做的伎倆。另外,我沒有提供枚舉值的名稱空間。

Sort::sort<int, std::vector<int>>(intVector, std::less<int>(), Sort::merge) 

謝謝你們!

+1

無關你的問題,但有你有一個共同的指向容器的特殊原因?這是相當罕見的,在許多情況下不需要。 –

+3

至於你的問題,我個人推廣甚至*進一步與模板類型,並使兩個第一個參數模板以及。甚至可以使函數模擬幾乎所有對容器起作用的[標準算法](http://en.cppreference.com/w/cpp/algorithm)函數,並將兩個迭代器作爲參數而不是容器(並因此放棄整個'Container'模板參數)。例如,如何使用模板使用'std :: less',爲什麼不看[[std :: map]](http://en.cppreference.com/w/cpp/container/map)? –

+0

這是我用C++編寫的第一批代碼之一,現在我正在重構它。指針是讓事情對我有用的第一件事。我知道它有多痛苦。一旦我找出爲什麼它不起作用,我將刪除指針。 –

回答

2
template <class Elem = int, class Container = std::vector<Elem>> 
    void sort(std::shared_ptr<Container> vectorPointer, 
       std::function<bool(Elem, Elem)> comparator = std::less<Elem>(), 
       Type type = selection) 

比較器類型取決於模板參數ELEM,所以當編譯器執行模板扣規則它要求呼叫者的設置值具有自變量的類型模式匹配類型。由於'less'和'function'不是同一類型,所以這個函數不是有效的匹配。

(不要混淆類型推導邏輯是相同的,與這些類型的實例打交道時所允許的轉換序列。)

如果你改變你的電話看起來像這樣它會工作(雖然很明顯,你不想做這道菜由於可怕的用戶體驗):

Sort::sort(shV, std::function<bool(int, int)>(std::less<int>()), Sort::merge); 

這樣,第二個參數的類型匹配模板所期待的。 上面的例子也解決了你使用'merge'枚舉器的問題,它在Sort命名空間中,並且需要命名空間限定。

一個小小的改變你的簽名,以作爲比較的另一個模板參數,是一種可能性:

template <class Elem = int, class Container = std::vector<Elem>, 
      class Compare = std::less<Elem>> 
void sort(std::shared_ptr<Container> vectorPointer, 
     Compare comparator = Compare(), 
     Type type = selection) { 
    switch (type) { 
     // ... 
    } 
+0

非常感謝您的解釋。我不知道簽名不匹配。從用戶角度來看,這絕對看起來更好。 –

+1

@ bartlomiej.n它還從函數調用中消除間接級別。 'std :: function' *有效*多態,並且調用'std :: function'包裝的可調用(即使'std :: function :: operator()'本身不是虛擬的)也存在虛擬調用開銷。通過直接將可調用對象作爲參數傳遞給它自己的類型,這種間接性不僅被刪除,而且編譯器甚至可以內聯可調用的調用。對於一個像'std :: less'一樣簡單的函數,每個比較的虛擬調用開銷是不可忽略的! – cdhowie

+0

@cdhowie我稍後會實施此更改。謝謝! –

1

如果您使用的是C++ 14,則您的std::function<bool(Elem, Elem)> comparator應爲 std::function<bool(const Elem&, const Elem&)>std::function<bool(auto,auto)>

+1

雖然你可以在C++ 14的lambda中使用'auto',但是'std :: function'類型的參數不能是'auto'。 – Jarod42

+0

@ Jarod42你是對的。感謝您的更正。 – LeDYoM

+0

這會改善什麼?我認爲按值設置參數將是最有效的方法 –