del*_*bly 6 c++ ienumerable stdvector stdset c++11
简单地说,如果我有一个集合和向量,我如何创建一个可以同时处理params的泛型方法.
我想要做的就是迭代任何类型的集合.听起来应该是微不足道的,但我错过了一些东西.
void printMeSomeStrings(somebaseclass<string> strings) {
for (auto& str : strings) {
cout << str << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
在C#中,我会传递IEnumerable或类似的东西.然后我可以迭代收集.
任何解释答案的一般性阅读将不胜感激.
您可以使用模板。例如:
#include <iostream>
template<typename C>
void foo(C const& c)
{
std::cout << "{ ";
for (auto const& x : c)
{
std::cout << x << " ";
}
std::cout << "}";
}
Run Code Online (Sandbox Code Playgroud)
以下是您将如何使用它:
#include <set>
#include <vector>
int main()
{
std::vector<int> v = {1, 2, 3};
foo(v);
std::cout << std::endl;
std::set<std::string> s = {"Hello,", "Generic", "World!"};
foo(s);
}
Run Code Online (Sandbox Code Playgroud)
第一个选项是将执行迭代的代码放在模板中。这需要将实现公开给每个使用它的人,这是有缺点的。
基本上,采用类型C
作为template
参数,然后根据该类型编写代码C
。
template<typename C>
void printMeSomeStrings(C&& strings) {
for (auto const& str : strings) {
cout << str << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您希望能够在接口和实现之间建立强大的屏障,C++11 方法将是在for
可迭代容器上进行类型擦除,然后公开for
可迭代容器,就像这样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) ) ) {}
};
Run Code Online (Sandbox Code Playgroud)
它将类型擦除容器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);
}
Run Code Online (Sandbox Code Playgroud)
这里发生的是,对于用于构造适配器的每种类型,我们为每种类型构建一个自定义实现。然后,我们存储指向该自定义类的抽象基类的指针,并对每次调用进行重定向。
这意味着任何专门std::begin
或定义其自身开始的内容都不需要相关:我们在使用时创建临时关系。
实例: http: //ideone.com/xOqBkI