簡體   English   中英

為STL容器傳遞模板化迭代器

[英]Pass Templated iterator for STL Container

對於我的C ++類(尚未涵蓋Boost)的練習,我在編寫模板化方法以接受兩個迭代器來匯總STL容器中的數值時遇到問題。
請考慮以下示例:

#include <iostream>
#include <iterator>
#include <vector>

template<typename T>
double Sum(const T & c) {
    return 42.0;    // implementation stubbed
}

// need help writing this method signature to accept two iterators
template<typename T>
double Sum(const typename T::const_iterator & begin,
           const typename T::const_iterator & end) {
    return 43.0;    // another implementation stub
}

int main() {
    std::vector<double> v;
    v.push_back(3.14);
    v.push_back(2.71);
    v.push_back(1.61);    // sums to 7.46

    std::cout << Sum(v) << ' '              // line 23
              << Sum(v.begin(), v.end())    // line 24
              << '\n';
}

我希望這段代碼輸出42 43 ,但它無法編譯。
g ++給我的錯誤是:

test_exercise2.cpp: In function ‘int main()’:
test_exercise2.cpp:24: error: no matching function for call to ‘Sum(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, __gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >)’

如果我注釋掉第24行,我會得到42作為輸出,正如預期的那樣。
無論第二個模板化方法是否存在,我都會得到相同的錯誤消息,因此由於某種原因,它無法將第24行的調用解析為我編寫的第二個方法。

對於接受兩個迭代器的方法,我必須具有什么簽名?


我之所以堅持這一點,是因為我需要支持對std::map<K, V>的第二個元素進行求和。 這將需要再調用兩次->second而不是解除引用迭代器:
1. template<typename K, typename V> double Sum(const std::map<K, V> & m); (我對這個沒問題)
2.另一個涉及地圖上的迭代器。

我覺得如果我能弄清楚如何為std::liststd::map指定迭代器的傳遞,我將能夠編寫std::map的方法。 我對使用模板模板的解決方案沒問題。


編輯:問題的准確措辭(省略非繳費句子)。
來自“上一個練習”的容器是std::vector<double>std::list<double>std::map<std::string, double>

創建一個名為Sum()的模板函數,它接受模板參數T作為輸入並返回一個double。 template參數將是一個容器。

  • 在實現中為結束獲取一個迭代器(T :: const_iterator)。 然后創建一個循環,迭代容器T並添加所有值。 最后歸還總和。
  • 在主程序中,為上一個練習中的不同容器調用Sum()函數。

創建的Sum()函數計算完整容器的總和。 還要創建一個Sum()函數來計算兩個迭代器之間的總和。 然后該函數使用模板參數作為迭代器類型,並接受兩個迭代器,即開始和結束迭代器。

你這太復雜了。 你想要一對任何類型的迭代器? 嗯,這就像兩個參數一樣簡單,任何類型。

template<typename Iterator>
double Sum(const Iterator& begin,
           const Iterator& end) {
    return 43.0;    // another implementation stub
}

問題解決了。

順便說一下,從C ++標准庫中獲取提示:如果你不能取消引用迭代器,那么讓用戶提供一個函數來從迭代器中獲取值。 不要特殊情況std::map因為明天有std::unordered_mapboost::multimap之后的那一天以及各種各樣的樂趣。 而如果我想你總結從按鍵 std::map ,而不是價值?

您的硬編碼案例有點復雜。 一對必須來自std::map的迭代器? 如果沒有明確的模板參數,甚至不確定。

template<typename K, typename V, typename Comp, typename Alloc>
double Sum(
    const std::map<K, V, Comp, Alloc>& map
) { ... }

請注意,我特意說它必須是std::map實例化。 這允許編譯器推導出參數。 從這里,您可以訪問迭代器。

正如DeadMG所說,簡單的方法是模板化迭代器的類型。 另一方面,通用約定是按值傳遞迭代器:

template <typename Iterator>
double Sum( Iterator begin, Iterator end );

至於為什么原始代碼不起作用,問題是容器的類型是不可推導的:

template <typename T>
double Sum( T::const_iterator begin, T::const_iterator end );
Sum( v.begin(), v.end() );        // [*] Assume v == const std::vector<double>&

當編譯器嘗試推斷Sum的參數類型時,它只能看到v.begin()v.end()返回的類型,它們是迭代器 從該類型,它無法猜測容器的類型。 為了能夠確定類型T是什么,它必須測試所有非模板類型,並生成模板類型的所有無限可能實例化,以查看它們是否具有與v.begin()的類型匹配的嵌套類型const_iterator v.end() 因為那是不可能實現的,語言首先禁止它。

除此之外,與注釋[*]相關 ,即使類型可以推斷,也會對函數的參數執行重載解析,而不是以后如何使用表達式。 在你的程序中, .begin()的參數是std::vector<double>非const lvalue 因為它不是const,所選擇的重載將產生一個非const迭代器(即使在你想要調用的函數中,也不需要讀取它)。

std::list中的迭代器與std::map迭代器進行對比時的區別特征是后者具有一對類型作為其value_type 也就是說,給定std::map<K, V>然后std::map<K, V>::value_typestd::iterator_traits<std::map<K, V>::iterator>::value_typestd::pair<const K, V>

因此,我建議您的Sum模板接受任何迭代器,但它不對迭代器(即*it )給出的元素進行操作,而是對'view': element(*it) 現在你可以注意確保element在面對一對時“做正確的事”。

作為提示,您可以將Sum聲明為以下(使用一些元編程來正確獲取返回類型):

namespace result_of {

// Second template parameter is an implementation detail
template<
    typename Iterator
    , typename ValueType = typename std::iterator_traits<Iterator>::value_type
>
struct Sum {
    // general case: sum over the value type directly
    typedef ValueType type;
};

// If an iterator admits an std::pair as its value_type then we end up here
template<typename Iterator, typename Key, typename Value>
struct Sum<Iterator, std::pair<Key, Value> > {
    // special case: sum over the second type of the value
    typedef Value type;
};

} // result_of

template<typename Iterator>
typename result_of::Sum<Iterator>::type Sum(Iterator begin, Iterator end);

暫無
暫無

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

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