例如,有一个行李系统:
class BagBase
{
public:
typedef std::vector<BagObj*> ObjVec;
virtual ObjVec FindObjs(const FinderBase& finder);
protected:
ObjVec Objs;
}
class Bag1 : public BagBase
{
public:
typedef std::vector<MyBagObj*> MyObjVec;
virtual ObjVec FindObjs(const FinderBase& finder);
// ignore ObjVec Objs in BagBase,
// store objects with another type (with more information)
// but you can still extract BagObj* from MyObjs through FindObjs
private:
MyObjVec MyObjs;
}
class Bag2 : public BagBase
{
// just use FindObjs defined in BagBase
}
我想使用FindObjs
实施std::find_if
,
例如:
struct FinderBase
{
virtual bool operator()(BagObj* o);
};
struct Finder1 : public FinderBase
{
virtual bool operator()(BagObj* o);
};
// and Finder2, Finder3, so on, each target to find by different conditions
实施virtual ObjVec BagBase::FindObjs(const FinderBase& finder);
之类的:
virtual ObjVec BagBase::FindObjs(const FinderBase& finder)
{
ObjVec results;
// a while loop execute std::find_if each time
// below is just a concept
while (...)
{
ObjVec::iterator it = std::find_if(Objs.begin(), Objs.end(), finder);
if (it != Objs.end())
{
results.push_back(*it);
}
++it;
}
}
因为Bag1
使用其他类型的向量,它可能看起来像:
virtual ObjVec Bag1::FindObjs(const FinderBase& finder)
{
ObjVec results;
while (...)
{
// the difference: MyObjVec
MyObjVec::iterator it = std::find_if(Objs.begin(), Objs.end(), finder);
if (it != Objs.end())
{
// extract Obj* from MyObj*
MyObj* my_obj = (*it);
Obj* obj = my_obj->obj;
results.push_back(obj);
}
++it;
}
}
问题是,std::find_if
复制finder
,
所以它确实知道它的实际类型(它可能是Finder1
或Finder2
),
它只是复制,好像它是一个FinderBase
对象。
virtual
FindObjs
是必须的,因为vector
种类不同,所以我无法通过finder
使用template
,但是这与std::find_if
的需要直接相矛盾,后者无法推断出finder
的实际类型。
那么这个问题的更好解决方案是什么?
可以混合使用virtual
和template
这个东西吗?
谢谢!
P.S。需要C ++ 03的解决方案,谢谢!
答案 0 :(得分:3)
将finder
对象包裹在reference_wrapper
中。 ref
和cref
可用于创建一个。
MyObjVec::iterator it = std::find_if(Objs.begine(), Objs.end(), std::ref(finder));
如果你使用的是前C ++ 11编译器,那就是Boost.Ref
编辑:
正如评论中指出的那样,只需将std::ref
替换为boost::ref
即可。这是因为与boost::reference_wrapper
不同,std::reference_wrapper
缺少operator()
。仅当std::reference_wrapper
包装可调用对象时,此运算符才会参与重载解析,从而允许它以可调用的方式透明地运行。
要从Boost获得相同的功能,我们需要使用boost::bind
来允许调用boost::reference_wrapper
中包含的可调用对象。
MyObjVec::iterator it = std::find_if(Objs.begine(), Objs.end(),
boost::bind<bool>(boost::ref(finder), _1));
Live demo显示std::ref
和boost::ref
的使用情况。
答案 1 :(得分:0)
我不确定我是否完全理解这个问题,但这是我从阅读中得到的...我不确定为什么std::ref
或std::cref
也需要.. std::find_if
似乎与多态对象和虚函数一起正常工作。
#include <algorithm>
#include <vector>
#include <iostream>
struct Object
{
void print() {std::cout<<"Object\n";}
virtual ~Object(){};
};
struct Integer : public Object
{
void print() {std::cout<<"Integer\n";}
virtual ~Integer(){}
};
struct Float : public Object
{
void print() {std::cout<<"Float\n";}
virtual ~Float(){}
};
struct FinderBase
{
virtual bool operator()(Object* obj){return obj;}
};
struct Finder : public FinderBase
{
virtual bool operator()(Object* obj){return obj;}
};
class Parent
{
protected:
std::vector<Object*> Objs;
public:
Parent() {Objs.push_back(new Object());}
virtual ~Parent() {delete Objs.back();}
virtual void find(FinderBase* finder);
};
void Parent::find(FinderBase* finder)
{
auto it = std::find_if(Objs.begin(), Objs.end(), *finder);
if (it != Objs.end())
{
typename decltype(Objs)::value_type obj = *it;
obj->print();
}
}
class Brother : public Parent
{
protected:
std::vector<Integer*> Objs;
public:
Brother() {Objs.push_back(new Integer());}
virtual ~Brother() {delete Objs.back();}
virtual void find(FinderBase* finder);
};
void Brother::find(FinderBase* finder)
{
auto it = std::find_if(Objs.begin(), Objs.end(), *finder);
if (it != Objs.end())
{
typename decltype(Objs)::value_type b = *it;
b->print();
}
}
class Sister : public Parent
{
protected:
std::vector<Float*> Objs;
public:
Sister() {Objs.push_back(new Float());}
virtual ~Sister() {delete Objs.back();}
virtual void find(FinderBase* finder);
};
void Sister::find(FinderBase* finder)
{
auto it = std::find_if(Objs.begin(), Objs.end(), *finder);
if (it != Objs.end())
{
typename decltype(Objs)::value_type s = *it;
s->print();
}
}
int main()
{
Parent P;
Brother B;
Sister S;
Finder finder;
P.find(&finder);
B.find(&finder);
S.find(&finder);
std::cout<<"\n\n";
Parent* ptr = new Parent();
ptr->find(&finder);
delete ptr;
Parent* Bptr = new Brother();
Bptr->find(&finder);
delete Bptr;
Parent* Sptr = new Sister();
Sptr->find(&finder);
delete Sptr;
return 0;
}
打印:
Object
Integer
Float
Object
Integer
Float
您可以尝试一下:http://ideone.com/2zQmT0