任何建议,使用给定的任意类型的参数做任意操作? [英] Any suggestion for doing an arbitrary operation using given arguments of arbitrary types?
问题描述
基本上我只是想使用任意类型的给定参数做一个任意操作。
参数类型基类是Var,Operation是操作的基类将对给定的参数执行。
我有Evaluator类,它们拥有使用opId映射的运算符集合。 Evaluator将根据evaluate()成员函数中给出的opId参数进行操作,然后evaluate()函数将搜索支持的操作符,它将接受参数类型和opId。
我想问的是,是否有任何有效的模式或算法,这将没有dynamic_cast >和/或循环操作符集合。
`
class Var {
public:
bool isValidVar );
static Var invalidVar();
}
template< typename T> class VarT:public Var {
public:
virtual const T getValue()const;
}
class Operator {
public:
virtual Var evaluate(const Var& a,const Var& b)= 0;
}
template< typename T> class AddOperator:public Operator {
public:
virtual Var evaluate(const Var& a,const Var& b)
{// dynamic_cast is slow!
const VarT< T> * varA = dynamic_cast< const VarT T *>(& a);
const VarT T * varB = dynamic_cast< const VarT T * *(& b);
if(varA&& varB)// operation supported
{
return VarT< T>(varA-> getValue()+ varA-> getValue());
}
return Var :: invalidVar(); //不支持此类型的操作
}
}
类Evaluator {
private:
std :: map< int,std :: vector< Operator>> operatorMap;
public:
virtual var evaluate(const Var& a,const Var& b,int opId)
{
std :: map< int,std :: vector< Operator> > :: iterator it = this-> operatorMap.find(opId);
if(it!= this-> operatorMap.end())
{
for(size_t i = 0; i< it-> second.size(); i ++)
{
Var result = it-> second.at(i).evaluate(a,b);
if(result.isValidVar())
{
return result;
}
}
}
//没有操作符映射,或没有操作符支持类型
return Var :: invalidVar();
}
}
`
添加了05 / 03/10:以下示例将演示runtime-traits如何工作
CommonHeader.h
#ifndef GENERIC_HEADER_INCLUDED
#define GENERIC_HEADER_INCLUDED
#include< map>
#include< vector>
#include< iostream>
//默认模板
模板< class T>
struct type_traits
{
static const int typeId = 0;
static const int getId(){return typeId; }
};
class Var
{
public:
virtual〜Var(){}
virtual int getType()const = 0;
virtual void print()const = 0;
}
template< typename T>
class VarT:public Var
{
T value;
public:
VarT(const T& v):value(v){}
virtual int getType()const {return type_traits T :: getId };
virtual void print()const {std :: cout<值<< std :: endl; };
const T& getValue()const {return value; }
};
class Operator
{
public:
virtual〜Operator(){}
virtual Var * evaluate(const Var& a,const Var& b )const = 0;
}
template< typename T>
class AddOperator:public Operator
{
public:
virtual Var * evaluate(const Var& a,const Var& b)const
{
//非常基本的条件保护
//允许只在类似类型中操作
//否则必须创建额外的兼容性checker
// ie。 AddOperator< Matrix>矩阵& int
//它也需要复杂的价值检索机制
//因为static_cast不再能被使用,因为未知的类型。
if((a.getType()== b.getType())&&
(a.getType()== type_traits< T> :: getId())&&
(b.getType()!= type_traits< void> :: getId()))
{
const VarT T * varA = static_cast< const VarT T * (& a);
const VarT T * varB = static_cast< const VarT T * *(& b);
return new VarT< T>(varA-> getValue()+ varB-> getValue());
}
return 0;
}
};
class Evaluator {
private:
std :: map< int,std :: vector< Operator *> operatorMap;
public:
void registerOperator(Operator * pOperator,int iCategory)
{
operatorMap [iCategory] .push_back(pOperator);
}
virtual Var * evaluate(const Var& a,const Var& b,int opId)
{
Var * pResult = 0;
std :: vector< Operator *>& opList = operatorMap.find(opId) - > second;
for(std :: vector< Operator *> :: const_iterator opIter = opList.begin();
opIter!= opList.end();
opIter ++)
pResult =(* opIter) - > evaluate(a,b);
if(pResult)
break;
}
返回pResult;
}
};
#endif
DataProvider标题
#ifdef OBJECTA_EXPORTS
#define OBJECTA_API __declspec(dllexport)
#else
#define OBJECTA_API __declspec(dllimport)
#endif
//这是common标头
#includeCommonHeader.h
class CFraction
{
public :
CFraction(void);
CFractions(int iNum,int iDenom);
CFraction(const CFraction& src);
int m_iNum;
int m_iDenom;
}
externCOBJECTA_API Operator * createOperator();
externCOBJECTA_API Var * createVar();
DataProvider实现
#includeFraction.h
//用户类型专门化
模板<>
struct type_traits< CFraction>
{
static const int typeId = 10;
static const int getId(){return typeId; }
};
std :: ostream& operator<<<(std :: ostream& os,const CFraction& data)
{
return os< 分子:< data.m_iNum<< @ Denominator:< data.m_iDenom<< std :: endl;
}
CFraction运算符+(const CFraction& lhs,const CFraction& rhs)
{
CFraction obj;
obj.m_iNum =(lhs.m_iNum * rhs.m_iDenom)+(rhs.m_iNum * lhs.m_iDenom);
obj.m_iDenom = lhs.m_iDenom * rhs.m_iDenom;
return obj;
}
OBJECTA_API运算符* createOperator(void)
{
return new AddOperator< CFraction> ;;
}
OBJECTA_API Var * createVar(void)
{
return new VarT< CFraction>(CFraction(1,4));
}
CFraction :: CFraction():
m_iNum(0),
m_iDenom(0)
{
} $ b b CFraction :: CFraction(int iNum,int iDenom):
m_iNum(iNum),
m_iDenom(iDenom)
{
}
CFraction :: CFraction CFract& src):
m_iNum(src.m_iNum),
m_iDenom(src.m_iDenom)
{
}
DataConsumer
#includeCommonHeader.h
#includewindows.h
//用户类型专门化
模板<>
struct type_traits< int>
{
static const int typeId = 1;
static const int getId(){return typeId; }
};
int main()
{
Evaluator e;
HMODULE hModuleA = LoadLibrary(ObjectA.dll);
if(hModuleA)
{
FARPROC pnProcOp = GetProcAddress(hModuleA,createOperator);
FARPROC pnProcVar = GetProcAddress(hModuleA,createVar);
//准备函数指针
typedef Operator *(* FACTORYOP)();
typedef Var *(* FACTORYVAR)();
FACTORYOP fnCreateOp = reinterpret_cast< FACTORYOP>(pnProcOp);
FACTORYVAR fnCreateVar = reinterpret_cast< FACTORYVAR>(pnProcVar);
//创建对象
Operator * pOp = fnCreateOp();
Var * pVar = fnCreateVar();
AddOperator< int> intOp;
AddOperator< double> doubleOp;
e.registerOperator(& intOp,0);
e.registerOperator(& doubleOp,0);
e.registerOperator(pOp,0);
VarT< int> i1(10);
VarT< double> d1(2.5);
VarT< float> f1(1.0f);
std :: cout<< Int Obj id:< i1.getType()<< std :: endl;
std :: cout<< Double Obj id:< d1.getType()<< std :: endl;
std :: cout<< Float Obj id:< f1.getType()<< std :: endl;
std :: cout<< Import Obj id:<< pVar-> getType()<< std :: endl;
Var * i_result = e.evaluate(i1,i1,0); // result = 20
Var * d_result = e.evaluate(d1,d1,0); // no result
Var * f_result = e.evaluate(f1,f1,0); // no result
Var * obj_result = e.evaluate(* pVar,* pVar,0); // result depend on data provider
Var * mixed_result1 = e.evaluate(f1,d1,0); // no result
Var * mixed_result2 = e.evaluate(* pVar,i1,0); // no result
obj_result-> print();
FreeLibrary(hModuleA);
}
return 0;
}
Basically i just want to do an arbitrary operation using given arguments of arbitrary types.
Argument type base class is Var, and Operation is base class of the operation that will executed for given arguments.
I have Evaluator class, that hold a collection of operators which mapped using opId. Evaluator will do operation based on opId argument given in evaluate() member function, then evaluate() function will do search for supported operator that will accept argument type and opId.
what I want to ask is, is there any efficient pattern or algorithm that will do this without dynamic_cast<> and/or looping through operator collection.
`
class Var {
public:
bool isValidVar();
static Var invalidVar();
}
template<typename T> class VarT : public Var {
public:
virtual const T getValue() const;
}
class Operator {
public:
virtual Var evaluate(const Var& a, const Var& b) = 0;
}
template<typename T> class AddOperator : public Operator {
public:
virtual Var evaluate(const Var& a, const Var& b)
{ //dynamic_cast is slow!
const VarT<T>* varA = dynamic_cast<const VarT<T>*>(&a);
const VarT<T>* varB = dynamic_cast<const VarT<T>*>(&b);
if(varA && varB) //operation supported
{
return VarT<T>(varA->getValue() + varA->getValue());
}
return Var::invalidVar(); //operation for this type is not supported
}
}
class Evaluator {
private:
std::map<int,std::vector<Operator>> operatorMap;
public:
virtual Var evaluate(const Var& a, const Var& b,int opId)
{
std::map<int,std::vector<Operator>>::iterator it = this->operatorMap.find(opId);
if(it != this->operatorMap.end())
{
for(size_t i=0 ; i<it->second.size() ; i++)
{
Var result = it->second.at(i).evaluate(a,b);
if(result.isValidVar())
{
return result;
}
}
}
//no operator mapped, or no operator support the type
return Var::invalidVar();
}
}
`
if you do not want to use dynamic_cast, consider adding type traits into your design.
Added 05/03/10 : The following sample will demonstrate how runtime-traits works
CommonHeader.h
#ifndef GENERIC_HEADER_INCLUDED
#define GENERIC_HEADER_INCLUDED
#include <map>
#include <vector>
#include <iostream>
// Default template
template <class T>
struct type_traits
{
static const int typeId = 0;
static const int getId() { return typeId; }
};
class Var
{
public:
virtual ~Var() {}
virtual int getType() const = 0;
virtual void print() const = 0;
};
template<typename T>
class VarT : public Var
{
T value;
public:
VarT(const T& v): value(v) {}
virtual int getType() const { return type_traits<T>::getId(); };
virtual void print() const { std::cout << value << std::endl; };
const T& getValue() const { return value; }
};
class Operator
{
public:
virtual ~Operator() {}
virtual Var* evaluate(const Var& a, const Var& b) const = 0;
};
template<typename T>
class AddOperator : public Operator
{
public:
virtual Var* evaluate(const Var& a, const Var& b) const
{
// Very basic condition guarding
// Allow operation within similar type only
// else have to create additional compatibility checker
// ie. AddOperator<Matrix> for Matrix & int
// it will also requires complicated value retrieving mechanism
// as static_cast no longer can be used due to unknown type.
if ( (a.getType() == b.getType()) &&
(a.getType() == type_traits<T>::getId()) &&
(b.getType() != type_traits<void>::getId()) )
{
const VarT<T>* varA = static_cast<const VarT<T>*>(&a);
const VarT<T>* varB = static_cast<const VarT<T>*>(&b);
return new VarT<T>(varA->getValue() + varB->getValue());
}
return 0;
}
};
class Evaluator {
private:
std::map<int, std::vector<Operator*>> operatorMap;
public:
void registerOperator(Operator* pOperator, int iCategory)
{
operatorMap[iCategory].push_back( pOperator );
}
virtual Var* evaluate(const Var& a, const Var& b, int opId)
{
Var* pResult = 0;
std::vector<Operator*>& opList = operatorMap.find(opId)->second;
for ( std::vector<Operator*>::const_iterator opIter = opList.begin();
opIter != opList.end();
opIter++ )
{
pResult = (*opIter)->evaluate( a, b );
if (pResult)
break;
}
return pResult;
}
};
#endif
DataProvider header
#ifdef OBJECTA_EXPORTS
#define OBJECTA_API __declspec(dllexport)
#else
#define OBJECTA_API __declspec(dllimport)
#endif
// This is the "common" header
#include "CommonHeader.h"
class CFraction
{
public:
CFraction(void);
CFraction(int iNum, int iDenom);
CFraction(const CFraction& src);
int m_iNum;
int m_iDenom;
};
extern "C" OBJECTA_API Operator* createOperator();
extern "C" OBJECTA_API Var* createVar();
DataProvider implementation
#include "Fraction.h"
// user-type specialization
template<>
struct type_traits<CFraction>
{
static const int typeId = 10;
static const int getId() { return typeId; }
};
std::ostream& operator<<(std::ostream& os, const CFraction& data)
{
return os << "Numerator : " << data.m_iNum << " @ Denominator : " << data.m_iDenom << std::endl;
}
CFraction operator+(const CFraction& lhs, const CFraction& rhs)
{
CFraction obj;
obj.m_iNum = (lhs.m_iNum * rhs.m_iDenom) + (rhs.m_iNum * lhs.m_iDenom);
obj.m_iDenom = lhs.m_iDenom * rhs.m_iDenom;
return obj;
}
OBJECTA_API Operator* createOperator(void)
{
return new AddOperator<CFraction>;
}
OBJECTA_API Var* createVar(void)
{
return new VarT<CFraction>( CFraction(1,4) );
}
CFraction::CFraction() :
m_iNum (0),
m_iDenom (0)
{
}
CFraction::CFraction(int iNum, int iDenom) :
m_iNum (iNum),
m_iDenom (iDenom)
{
}
CFraction::CFraction(const CFraction& src) :
m_iNum (src.m_iNum),
m_iDenom (src.m_iDenom)
{
}
DataConsumer
#include "CommonHeader.h"
#include "windows.h"
// user-type specialization
template<>
struct type_traits<int>
{
static const int typeId = 1;
static const int getId() { return typeId; }
};
int main()
{
Evaluator e;
HMODULE hModuleA = LoadLibrary( "ObjectA.dll" );
if (hModuleA)
{
FARPROC pnProcOp = GetProcAddress(hModuleA, "createOperator");
FARPROC pnProcVar = GetProcAddress(hModuleA, "createVar");
// Prepare function pointer
typedef Operator* (*FACTORYOP)();
typedef Var* (*FACTORYVAR)();
FACTORYOP fnCreateOp = reinterpret_cast<FACTORYOP>(pnProcOp);
FACTORYVAR fnCreateVar = reinterpret_cast<FACTORYVAR>(pnProcVar);
// Create object
Operator* pOp = fnCreateOp();
Var* pVar = fnCreateVar();
AddOperator<int> intOp;
AddOperator<double> doubleOp;
e.registerOperator( &intOp, 0 );
e.registerOperator( &doubleOp, 0 );
e.registerOperator( pOp, 0 );
VarT<int> i1(10);
VarT<double> d1(2.5);
VarT<float> f1(1.0f);
std::cout << "Int Obj id : " << i1.getType() << std::endl;
std::cout << "Double Obj id : " << d1.getType() << std::endl;
std::cout << "Float Obj id : " << f1.getType() << std::endl;
std::cout << "Import Obj id : " << pVar->getType() << std::endl;
Var* i_result = e.evaluate(i1, i1, 0); // result = 20
Var* d_result = e.evaluate(d1, d1, 0); // no result
Var* f_result = e.evaluate(f1, f1, 0); // no result
Var* obj_result = e.evaluate(*pVar, *pVar, 0); // result depend on data provider
Var* mixed_result1 = e.evaluate(f1, d1, 0); // no result
Var* mixed_result2 = e.evaluate(*pVar, i1, 0); // no result
obj_result->print();
FreeLibrary( hModuleA );
}
return 0;
}
这篇关于任何建议,使用给定的任意类型的参数做任意操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!