第一個選項是把代碼做一個模板的迭代。這要求將實施暴露給使用它的每個人,這有缺點。
基本上,參數爲C
作爲template
參數,然後根據該類型C
編寫代碼。
template<typename C>
void printMeSomeStrings(C&& strings) {
for (auto const& str : strings) {
cout << str << endl;
}
}
如果你希望能夠有接口和實現之間有很強的阻隔,在C++ 11的辦法是搞類型擦除在for
-iterable容器,然後暴露for
-iterable容器,就像std::function
的工作方式一樣。
這更棘手。我個人認爲編寫一個for_each
函數比編寫一個完整的迭代適配器更容易。如果您想要完整的容器迭代類型擦除對象,請從boost
開始,或者在下面問我,我可能會這樣做。
但是,for_each
適配器很容易。
#include <functional>
#include <utility>
#include <iterator>
#include <memory>
template<typename T>
struct for_each_helper_interface {
virtual ~for_each_helper_interface() {}
virtual void for_each(std::function< void(T) > const&) = 0;
};
template<typename C, typename T>
struct for_each_helper:for_each_helper_interface<T> {
C& c;
for_each_helper(C& in):c(in) {}
virtual void for_each(std::function< void(T) > const& f) override final {
for(auto&& x:c) {
f(x);
}
}
};
template<typename T>
struct for_each_adaptor {
std::unique_ptr<for_each_helper_interface<T>> pImpl;
void for_each(std::function< void(T) > const& f) {
if (pImpl) {
pImpl->for_each(f);
}
}
template<typename C>
for_each_adaptor(C&& c): pImpl(new for_each_helper<C, T>(std::forward<C>(c))) {}
};
將類型擦除T
容器(或類型轉換爲T
!),並公開一個for_each
方法,可以讓你遍歷容器的內容。使用這樣的:
#include <set>
#include <iostream>
#include <vector>
void print_stufF(for_each_adaptor<std::string const&> c) {
c.for_each([&](std::string const&s){
std::cout << s << "\n";
});
}
int main() {
std::set<std::string> s;
s.insert("hello");
s.insert("world");
print_stuff(s);
std::vector<std::string> v;
v.push_back("hola");
v.push_back("bola");
print_stuff(v);
}
這到底是怎麼回事的是,對於所使用的每個類型來構建我們的適配器,我們建立的每個自定義實現。然後,我們存儲一個指向此自定義類的抽象基類的指針,併爲每個調用重定向它。
這意味着什麼專業std::begin
或定義自己的開始不需要相關:我們創建專用關係,而不是在使用點。
活生生的例子:http://ideone.com/xOqBkI
Boost已經擁有'any_range',它將執行類似於'std :: function'的類型擦除。 – 2013-05-15 12:22:27