基本上我只想使用任意类型的给定参数进行任意操作。
参数类型基类是 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(); //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();
}
}
`
最佳答案
如果您不想使用 dynamic_cast,请考虑在您的设计中添加类型特征。
添加于 05/03/10:以下示例将演示运行时特征的工作原理
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();
数据提供者实现
#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)
{
}
数据消费者
#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;
}
关于c++ - 使用任意类型的给定参数进行任意操作的任何建议?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2377636/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t