Первый вариант поставить код делает на итерации в шаблоне. Это требует раскрытия реализации всем, кто ее использует, что имеет недостатки.
В принципе, возьмите тип 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'. –