C++ 如何多态地使用copy_if()?
此代码尝试在多态指针向量上使用copy_:C++ 如何多态地使用copy_if()?,c++,stl,polymorphism,C++,Stl,Polymorphism,此代码尝试在多态指针向量上使用copy_: #include <iostream> #include <algorithm> #include <vector> using namespace std; class AbstractBase { public: virtual bool IsDerived1() const { return false; } virtual void Print() const =
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class AbstractBase
{
public:
virtual bool IsDerived1() const { return false; }
virtual void Print() const = 0;
};
class Derived1 : public AbstractBase
{
public:
virtual bool IsDerived1() const { return true; }
virtual void Print() const { cout << "Derived1" << endl; }
};
class Derived2 : public AbstractBase
{
public:
virtual void Print() const { cout << "Derived2" << endl; }
};
// This function returns the elements of v that are of type Derived1.
vector<Derived1*> SelectDerived1(const vector<AbstractBase*>& v)
{
vector<Derived1*> derived1s;
#define USE_COPY_IF 0
#if USE_COPY_IF
// attempt to use copy_if - does not compile:
// /usr/include/c++/4.7/bits/stl_algo.h:990:6:
// error: invalid conversion from 'AbstractBase*' to 'Derived1*'
// [-fpermissive]
copy_if(v.begin(), v.end(), derived1s.begin(),
[](AbstractBase* elem){ return elem->IsDerived1(); });
#else
for (auto it = v.begin(); it != v.end(); ++it)
if ((*it)->IsDerived1())
derived1s.push_back(static_cast<Derived1*>(*it));
#endif
return derived1s;
}
int main()
{
vector<AbstractBase*> v;
Derived1* d1 = new Derived1;
Derived2* d2 = new Derived2;
v.push_back(d1);
v.push_back(d2);
vector<Derived1*> derived1s = SelectDerived1(v);
for (auto it = derived1s.begin(); it != derived1s.end(); ++it)
(*it)->Print();
delete d1;
delete d2;
return 0;
}
但我无法让它与copy_if一起工作-请参阅评论中的错误消息
没有办法吗?如果标准中缺少函数转换,您可能需要定义函数转换:
template <class InIt, class OutIt, class Pred, class Trafo>
OutIt transform_if (
InIt begin_in, InIt end_in,
OutIt begin_out,
Pred predicate,
Trafo trafo
) {
OutIt itout = begin_out;
for (InIt itin = begin_in; itin != end_in; ++itin) {
if (predicate (*itin)) {
(*itout) = trafo (*itin);
++itout;
}
}
}
然后写:
transform_and_keep_if(v.begin(), v.end(), derived1s.begin(),
[](AbstractBase* elem){ return dynamic_cast<Derived1*> (elem); },
[](Derived1* elem){ return elem != NULL; },
);
如果标准中缺少函数转换,则可能需要定义函数转换。\u:
template <class InIt, class OutIt, class Pred, class Trafo>
OutIt transform_if (
InIt begin_in, InIt end_in,
OutIt begin_out,
Pred predicate,
Trafo trafo
) {
OutIt itout = begin_out;
for (InIt itin = begin_in; itin != end_in; ++itin) {
if (predicate (*itin)) {
(*itout) = trafo (*itin);
++itout;
}
}
}
然后写:
transform_and_keep_if(v.begin(), v.end(), derived1s.begin(),
[](AbstractBase* elem){ return dynamic_cast<Derived1*> (elem); },
[](Derived1* elem){ return elem != NULL; },
);
您可以使用std::partition在一次过程中对v进行分区,将所有派生的1指针放在向量的开头,然后调用std::transform来实际执行复制。代码如下所示:
auto deriveds_end = std::partition(v.begin(), v.end(),
[](AbstractBase* e){
return e->IsDerived1();
});
std::transform(v.begin(), deriveds_end,
std::back_inserter(derived1s),
[](AbstractBase* e){
return static_cast<Derived1*>(e);
});
没有比这更简洁的了。您可以使用std::partition一次性对v进行分区,将所有派生的1指针放在向量的开头,然后调用std::transform来实际执行复制。代码如下所示:
auto deriveds_end = std::partition(v.begin(), v.end(),
[](AbstractBase* e){
return e->IsDerived1();
});
std::transform(v.begin(), deriveds_end,
std::back_inserter(derived1s),
[](AbstractBase* e){
return static_cast<Derived1*>(e);
});
没有比这更简洁的了。您知道,即使考虑到elem->IsDerived1检查,这通常也是不安全的吗?任何人都可以创建一个新的子类,该子类不是Derived1的子类型,但从IsDerived1返回true。手动复制中执行的静态转换不是由std::copy执行的,因此,它试图将包含一种类型的集合复制到一个完全不同类型的集合中,这当然不起作用。您可以将copy_if与dynamic_cast结合,并将其复制到另一个AbstractBase*和std::transform向量中进行转换。@Mahesh您确定将USE_copy_if设置为1吗?!链接中的代码显示它仍然设置为0。您知道这通常不是类型安全的,即使考虑到elem->IsDerived1检查?任何人都可以创建一个新的子类,该子类不是Derived1的子类型,但从IsDerived1返回true。手动复制中执行的静态转换不是由std::copy执行的,因此,它试图将包含一种类型的集合复制到一个完全不同类型的集合中,这当然不起作用。您可以将copy_if与dynamic_cast结合,并将其复制到另一个AbstractBase*和std::transform向量中进行转换。@Mahesh您确定将USE_copy_if设置为1吗?!链接中的代码显示它仍然设置为0。在这里使用std::function有什么好处?它更灵活,因为您可以传递任何类似对象的函数。一旦在lambda函数的[]内捕获局部变量,就需要std::function,因为lambda将是一个对象。lambda始终是一个对象,即使它不捕获任何内容。如果将最后两个参数模板化,仍然可以传递任何类似于对象的函数。任何可以在函数调用中用作后缀表达式的东西都可以正常工作。当您希望将函数对象存储在某个位置时,函数非常有用。在这里,这是不必要的混乱。你是说模板输出转换\u如果/*…*/Pred Pred,Trafo Trafo{…}?倾向于认为至少短一点比较好。好吧,我改了。谢谢。在这里使用std::function有什么好处?它更灵活,因为您可以传递像object这样的任何函数。一旦在lambda函数的[]内捕获局部变量,就需要std::function,因为lambda将是一个对象。lambda始终是一个对象,即使它不捕获任何内容。如果将最后两个参数模板化,仍然可以传递任何类似于对象的函数。任何可以在函数调用中用作后缀表达式的东西都可以正常工作。当您希望将函数对象存储在某个位置时,函数非常有用。在这里,这是不必要的混乱。你是说模板输出转换\u如果/*…*/Pred Pred,Trafo Trafo{…}?倾向于认为至少短一点比较好。好吧,我改了。非常感谢。
for(auto i : v)
if(i->IsDerived1())
derived1s.push_back(static_cast<Derived1*>(i);