![](/img/trans.png)
[英]Accept templated parameter of stl_container_type<string>::iterator
[英]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::list
和std::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_map
和boost::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_type
和std::iterator_traits<std::map<K, V>::iterator>::value_type
是std::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.