任何建议,使用给定的任意类型的参数做任意操作? [英] Any suggestion for doing an arbitrary operation using given arguments of arbitrary types?

查看:134
本文介绍了任何建议,使用给定的任意类型的参数做任意操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上我只是想使用任意类型的给定参数做一个任意操作。



参数类型基类是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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆