2015-06-03 60 views
3

有人可以解釋我從cppreference網站的樣本中的幾點? 該技術描述了函數重載取決於迭代器類型。 前兩個使用「使用」的typedef很容易理解。 的問題涉及到ALG功能:解釋示例代碼從cppreference

  1. 在模板參數列表 - 「類型名稱= ...」不帶參數的名字,這是否意味着使用默認值,而在函數調用來覆蓋這個能力?
  2. 我理解使用第二個模板參數的權利 - 該函數將在只有通過迭代器類型和預期的迭代器標籤類型相等的情況下生成?

  3. 你能解釋第三模板參數的使用在第二函數ALG和註釋有:

「類型名稱=空隙> //虛設值,以避免模板重新定義錯誤 「

該件的代碼是在這裏(http://en.cppreference.com/w/cpp/iterator/iterator_tags):

template<typename Condition, typename T = void> 
using EnableIf_t = typename std::enable_if<Condition::value, T>::type; 

template<typename Iterator, typename IteratorTag> 
using IsSameIteratorCond = 
    std::is_same<IteratorTag, 
    typename std::iterator_traits<Iterator>::iterator_category>; 

template< 
    typename BDIter, 
    typename = EnableIf_t<IsSameIteratorCond<BDIter, std::bidirectional_iterator_tag>>> 
void alg(BDIter, BDIter) 
{ 
    std::cout << "alg() called for bidirectional iterator\n"; 
} 

template< 
    typename RAIter, 
    typename = EnableIf_t<IsSameIteratorCond<RAIter, std::random_access_iterator_tag>>, 
    typename = void> // dummy value to avoid template re-definition error 
void alg(RAIter, RAIter) 
{ 
    std::cout << "alg() called for random-access iterator\n"; 
} 

int main() 
{ 
    std::vector<int> v; 
    alg(v.begin(), v.end()); 

    std::list<int> l; 
    alg(l.begin(), l.end()); 
} 

回答

3
  1. typename = ...聲明未命名的模板參數。客戶端代碼仍然可以覆蓋它,但該參數不能在函數定義中使用。這是因爲第二個模板參數用於利用SFINAE,而不是用於定義要使用的類型。

  2. 更正,如果迭代器類型與預期的不同,則該函數將從過載候選集合中移除。

  3. 因爲默認值不是模板簽名的一部分,所以需要使用dummy參數,因此alg的兩個版本將試圖定義相同的函數模板。

使用默認值和虛擬參數是很醜陋給我,我寧願使用標籤調度:

template<typename BDIter> 
void alg(BDIter, BDIter, std::bidirectional_iterator_tag) 
{ 
    std::cout << "alg() called for bidirectional iterator\n"; 
} 

template <typename RAIter> 
void alg(RAIter, RAIter, std::random_access_iterator_tag) 
{ 
    std::cout << "alg() called for random-access iterator\n"; 
} 

template <typename It> 
void alg(It a, It b) 
{ 
    return alg(a, b, typename std::iterator_traits<It>::iterator_category{}); 
} 
+0

謝謝。不知道「默認值不是模板簽名的一部分」,你能否在C++標準或cppreference網站上給我一個鏈接? – amigo421

+0

我無法找到一個簡潔的參考,但想一想函數聲明中的模擬;如果函數只在默認參數上有所不同,那麼它們顯然會試圖聲明具有相同簽名的函數。 – TartanLlama

1
  1. 不,用戶可以覆蓋參數。命名參數 是可選的。如果你不使用它,你不必這樣做。
  2. 是的。標籤必須等於std::bidirectional_iterator_tag 第一次過載,std::random_access_iterator_tag爲 第二次。
  3. 沒有第三個模板參數,兩個函數聲明將是相同的,這是非法的。他們 要麼根據參數,返回類型,名稱或模板 參數(這是這裏的情況)有所不同。