C ++虚拟模板方法
我有一个抽象类(我知道它不会以这种方式编译,但它是为了理解我想要做的):
class AbstractComputation { public: template <class T> virtual void setData(std::string id, T data); template <class T> virtual T getData(std::string id); }; class Computation : public AbstractComputation { public: template <class T> void setData(std::string id, T data); template <class T> T getData(std::string id, T data); };
所以当我调用setData<double>("foodouble", data)
我想把double确定的foodouble
(这里不是主要关心的内部机制)设置为double数据。
那么该怎么做?
我认为有可能是通过键入类似virtual void setData<double>(std::string id, double data)
但我不知道该怎么做。
问题是你不能混合静态时间多态性(模板)和运行时多态性很容易。 在你的例子中,语言不允许特定的结构的原因是有可能是无限的不同的types,可以实例化你的模板成员函数,这又意味着编译器将不得不生成代码来dynamic调度这些types,是不可行的。
在这里可以做不同的事情来解决这个限制,基本上要么是拿走静态的,要么是dynamic的多态。 从等式中去除dynamic多态性可以通过提供一个不是派生的types来完成,存储<key,value>
映射,然后提供只在基本级别parsing的模板:
class AbstractComputation { public: template <typename T> void setData( std::string const & id, T value ) { m_store.setData( id, value ); } template <typename T> T getData( std::string const & id ) const { return m_store.getData<T>( id ); } protected: ValueStore m_store; };
现在派生类可以从基地访问ValueStore
,并且不需要多态性。 (这也可以通过在AbstractComputation
直接实现这个function来完成,但是分开关注也许是有意义的)
另一种select是维护运行时多态,但是除去静态多态。 这可以通过在基类上执行types擦除来完成,然后分派到采用types擦除参数的适当(非模板化)函数。 最简单的版本就是使用boost::any
:
class AbstractComputation { public: template <typename T> void setData( std::string const & id, T value ) { setDataImpl( id, boost::any( value ) ); } template <typename T> T getData( std::string const & id ) const { boost::any res = getDataImpl( id ); return boost::any_cast<T>( res ); } protected: virtual void setDataImpl( std::string const & id, boost::any const & value ) = 0; virtual boost::any getDataImpl( std::string const & id ) const = 0; };
如何实现types擦除在引擎盖下是有趣的,但超出范围在这里,重要的是,一个boost::any
是一个具体(非模板)types,可以存储任何types的内部types擦除的参数,同时允许对数据进行types安全的检索。
在某些情况下,将模板从方法级别移动到类级别可能就足够了,例如:
#include <iostream> template<typename T> class AbstractComputation { public: virtual void setData(std::string id, T data) { std::cout << "base" << std::endl; } }; template<typename T> class Computation : public AbstractComputation<T> { public: virtual void setData(std::string id, T data) { std::cout << "derived" << std::endl; } }; int main() { AbstractComputation<int> *x = new Computation<int>(); x->setData("1", -1); delete x; return 0; }
首先,你不能有virtual
模板function。 由于模板在编译时被parsing,所以virtual
将不起作用,因为编译器不知道要select哪个模板。 看到这里 ,更多关于这方面的信息。
使用boost::any
来接受数据,然后当你真正设置时,从中获取正确的types。
你可以在你的情况下使用boost::any
。
virtual void setData(std::string id, boost::any data);
这是一个封装,几乎可以封装任何东西。
更多的信息在这个答案类似的话题 。
如果您事先知道可能的types列表,预处理器可能会有所帮助:
#define MY_CLASSES MYTYPE(int) MYTYPE(float) MYTYPE(double) class AbstractComputation { public: # define MYTYPE(T) virtual void setData(std::string id, T data)=0;\ virtual void getData(std::string id, T& dst_data)=0; MY_CLASSES # undef MYTYPE }; class Computation : public AbstractComputation { public: # define MYTYPE(T) virtual void setData(std::string id, T data){std::cout<<"writing: "<<data<<std::endl;}\ virtual void getData(std::string id, T& dst_data){dst_data=0;/*put your actual implementation here*/} MY_CLASSES # undef MYTYPE };
如果你不知道可能的types的完整列表,或许,你的问题是无法解决的。 types擦除,如别人所说,也可能有所帮助..但不是在所有情况下。