Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对于使用任意类型的给定参数执行任意操作,有什么建议吗?_C++_Design Patterns_Generic Programming_Dynamic Cast - Fatal编程技术网

C++ 对于使用任意类型的给定参数执行任意操作,有什么建议吗?

C++ 对于使用任意类型的给定参数执行任意操作,有什么建议吗?,c++,design-patterns,generic-programming,dynamic-cast,C++,Design Patterns,Generic Programming,Dynamic Cast,基本上,我只想使用任意类型的给定参数执行任意操作 参数类型基类是Var,操作是将为给定参数执行的操作的基类 我有一个Evaluator类,它包含使用opId映射的运算符集合。Evaluator将根据evaluate()成员函数中给定的opId参数执行操作,然后evaluate()函数将搜索接受参数类型和opId的受支持运算符 我想问的是,是否有任何有效的模式或算法可以实现这一点,而无需动态强制转换和/或通过操作符集合循环 ` class Var { public: bool isVali

基本上,我只想使用任意类型的给定参数执行任意操作

参数类型基类是Var,操作是将为给定参数执行的操作的基类

我有一个Evaluator类,它包含使用opId映射的运算符集合。Evaluator将根据evaluate()成员函数中给定的opId参数执行操作,然后evaluate()函数将搜索接受参数类型和opId的受支持运算符

我想问的是,是否有任何有效的模式或算法可以实现这一点,而无需动态强制转换和/或通过操作符集合循环

`

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();
    }
}
类变量{
公众:
bool isValidVar();
静态变量invalidVar();
}
模板类VarT:public Var{
公众:
虚拟常量getValue()常量;
}
类运算符{
公众:
虚拟Var评估(常数Var&a、常数Var&b)=0;
}
模板类AddOperator:公共运算符{
公众:
虚拟Var评估(常数Var&a、常数Var&b)
{//dynamic\u cast太慢了!
const VarT*varA=动态施法(&a);
const VarT*varB=动态强制转换(&b);
if(varA&&varB)//支持的操作
{
返回VarT(varA->getValue()+varA->getValue());
}
return Var::invalidVar();//不支持此类型的操作
}
}
班级评估员{
私人:
映射运算符映射;
公众:
虚拟Var评估(常量Var&a、常量Var&b、int opId)
{
std::map::iterator it=this->operatorMap.find(opId);
if(it!=this->operatorMap.end())
{
对于(size_t i=0;isecond.size();i++)
{
Var result=it->second.at(i).评估(a,b);
if(result.isValidVar())
{
返回结果;
}
}
}
//没有映射的运算符,或者没有运算符支持该类型
返回Var::invalidVar();
}
}

`

如果可以修改类型
Var
,则可以为参数类型添加类型ID。但是,在执行操作时,在某些时候,您必须始终使用
动态\u cast
。如果您的类型和操作在编译时被固定,您可以使用模板(特别是容器)来完成整个事情。

< P>如果您不想使用DyrimeCype,请考虑将类型特征添加到您的设计中。

添加于2010年3月5日:以下示例将演示运行时特性是如何工作的

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
数据提供者实现

#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)
{
}
#包括“分数.h”
//用户类型专门化
模板
结构类型特征
{
静态常量int typeId=10;
static const int getId(){return typeId;}
};

std::ostream&operator您的示例代码包含许多错误,包括切片问题

我不是100%确定,但我似乎记得您可以使用
const type\u info*
作为地图的键

如果是这样,您可以使用如下内容。它并不是没有RTTI(
type\u info
),但是由于Evaluator已经检查了TypeID,所以您可以使用
static\u cast
,而不是
dynamic\u cast
(但现在代码不再盲目地搜索要应用的正确操作符,这并不重要)

当然,在内存管理方面,下面的内容是完全不同的。使用您选择的智能指针重新实现

#include <map>
#include <typeinfo>
#include <cassert>

#include <iostream>

struct CompareTypeinfo
{
    bool operator()(const std::type_info* a, const std::type_info* b) const
    {
        return a->before(*b);
    }
};

class Var {
public:
    virtual ~Var() {}
    virtual const std::type_info& getType() const = 0;

    virtual void print() const = 0;
};

template<typename T> class VarT : public Var {
    T value;
public:
    VarT(const T& v): value(v) {}
    const T& getValue() const { return value; }
    virtual const std::type_info& getType() const { return typeid(T); }  

    virtual void print() const { std::cout << value << '\n'; } 
};

class Operator {
public:
    virtual ~Operator() {}
    virtual Var* evaluate(const Var& a, const Var& b) const = 0;
    virtual const std::type_info& getType() const = 0;
};

template<typename T> class AddOperator : public Operator {
public:
    typedef T type;
    virtual const std::type_info& getType() const { return typeid(T); }
    virtual Var* evaluate(const Var& a, const Var& b) const
    {   
        //it is the responsibility of Evaluator to make sure that the types match the operator            
        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());
    }
};

class Evaluator {
private:
    typedef std::map<const std::type_info*, Operator*, CompareTypeinfo> TypedOpMap;
    typedef std::map<int, TypedOpMap> OpMap;
    OpMap operatorMap;
public:
    template <class Op>
    void registerOperator(int opId)
    {
        operatorMap[opId].insert(std::make_pair(&typeid(typename Op::type), new Op));
    }
    Var* evaluate(const Var& a, const Var& b,int opId)
    {
        OpMap::const_iterator op = operatorMap.find(opId);
        if (op != operatorMap.end() && a.getType() == b.getType()) {
            TypedOpMap::const_iterator typed_op = op->second.find(&a.getType());
            if (typed_op != op->second.end()) {
                //double-checked
                assert(typed_op->second->getType() == a.getType());
                return typed_op->second->evaluate(a, b);
            }
        }
        return 0;
    }
};

int main()
{
    Evaluator e;

    e.registerOperator<AddOperator<int> >(0);
    e.registerOperator<AddOperator<double> >(0);

    VarT<int> i1(10), i2(20);
    VarT<double> d1(2.5), d2(1.5);
    VarT<float> f1(1.0), f2(2.0);

    Var* i_result = e.evaluate(i1, i2, 0);
    Var* d_result = e.evaluate(d1, d2, 0);
    Var* f_result = e.evaluate(f1, f2, 0);
    Var* mixed_result = e.evaluate(i1, d2, 0);

    assert(i_result != 0);
    assert(d_result != 0);
    assert(f_result == 0); //addition not defined for floats in Evaluator
    assert(mixed_result == 0); //and never for mixed types

    i_result->print(); //30
    d_result->print(); //4.0
}
#包括
#包括
#包括
#包括
结构CompareTypeinfo
{
布尔运算符()(常数std::type_info*a,常数std::type_info*b)常数
{
返回a->before(*b);
}
};
类变量{
公众:
虚拟~Var(){}
虚拟常量std::type_info&getType()常量=0;
虚空打印()常量=0;
};
模板类VarT:public Var{
T值;
公众:
VarT(const T&v):值(v){
常量T&getValue()常量{返回值;}
虚拟常量std::type_info&getType()常量{return typeid(T);}
虚空打印()常量{std::cout getValue());
}
};
班级评估员{
私人:
typedef std::map TypedOpMap;
typedef std::map OpMap;
OpMap运算符映射;
公众:
模板
无效注册表运算符(int opId)
{
运算符映射[opId]。插入(std::make_pair)(&typeid(typename Op::type),new Op));
}
Var*评估(常数Var&a、常数Var&b、内部opId)
{
常量迭代器op=operatorMap.find(opId);
if(op!=operatorMap.end()&&a.getType()==b.getType()){
TypedOpMap::const_iterator typed_op=op->second.find(&a.getType());
if(键入的_op!=op->second.end()){
//反复检查
断言(typed_op->second->getType()==a.getType());
返回键入的操作->第二次->评估(a,b);
}
}
返回0;
}
};
int main()
{
评价者e;
e、 寄存器运算符(0);
e、 寄存器运算符(0);
varti1(10),i2(20);
变量d1(2.5)、d2(1.5);
变异系数f1(1.0),f2(2.0);
Var*i_result=e.evaluate(i1,i2,0);
Var*d_结果=e.评估(d1,d2,0);
Var*f_结果=e.评估(f1,f2,0);
Var*mixed_result=e.evaluate(i1,d2,0);
断言(i_结果!=0);
断言(d_结果!=0);
assert(f_result==0);//未为计算器中的浮点定义加法
assert(mixed_result==0);//并且从不用于混合类型
i_结果->打印();//30
d_结果->打印();//4.0
}

请澄清,您似乎有几个操作集合。您的OpId对应于多个操作。您希望使用哪种操作的标准是什么?是的,对于每个opId,它可能有多个运算符,要使用的运算符是可以接受给定参数类型的运算符。例如,我有AddOperator,AddOperator,AddOperator,AddOperator,所有这些操作符
#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;
}
#include <map>
#include <typeinfo>
#include <cassert>

#include <iostream>

struct CompareTypeinfo
{
    bool operator()(const std::type_info* a, const std::type_info* b) const
    {
        return a->before(*b);
    }
};

class Var {
public:
    virtual ~Var() {}
    virtual const std::type_info& getType() const = 0;

    virtual void print() const = 0;
};

template<typename T> class VarT : public Var {
    T value;
public:
    VarT(const T& v): value(v) {}
    const T& getValue() const { return value; }
    virtual const std::type_info& getType() const { return typeid(T); }  

    virtual void print() const { std::cout << value << '\n'; } 
};

class Operator {
public:
    virtual ~Operator() {}
    virtual Var* evaluate(const Var& a, const Var& b) const = 0;
    virtual const std::type_info& getType() const = 0;
};

template<typename T> class AddOperator : public Operator {
public:
    typedef T type;
    virtual const std::type_info& getType() const { return typeid(T); }
    virtual Var* evaluate(const Var& a, const Var& b) const
    {   
        //it is the responsibility of Evaluator to make sure that the types match the operator            
        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());
    }
};

class Evaluator {
private:
    typedef std::map<const std::type_info*, Operator*, CompareTypeinfo> TypedOpMap;
    typedef std::map<int, TypedOpMap> OpMap;
    OpMap operatorMap;
public:
    template <class Op>
    void registerOperator(int opId)
    {
        operatorMap[opId].insert(std::make_pair(&typeid(typename Op::type), new Op));
    }
    Var* evaluate(const Var& a, const Var& b,int opId)
    {
        OpMap::const_iterator op = operatorMap.find(opId);
        if (op != operatorMap.end() && a.getType() == b.getType()) {
            TypedOpMap::const_iterator typed_op = op->second.find(&a.getType());
            if (typed_op != op->second.end()) {
                //double-checked
                assert(typed_op->second->getType() == a.getType());
                return typed_op->second->evaluate(a, b);
            }
        }
        return 0;
    }
};

int main()
{
    Evaluator e;

    e.registerOperator<AddOperator<int> >(0);
    e.registerOperator<AddOperator<double> >(0);

    VarT<int> i1(10), i2(20);
    VarT<double> d1(2.5), d2(1.5);
    VarT<float> f1(1.0), f2(2.0);

    Var* i_result = e.evaluate(i1, i2, 0);
    Var* d_result = e.evaluate(d1, d2, 0);
    Var* f_result = e.evaluate(f1, f2, 0);
    Var* mixed_result = e.evaluate(i1, d2, 0);

    assert(i_result != 0);
    assert(d_result != 0);
    assert(f_result == 0); //addition not defined for floats in Evaluator
    assert(mixed_result == 0); //and never for mixed types

    i_result->print(); //30
    d_result->print(); //4.0
}