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擦除,如别人所说,也可能有所帮助..但不是在所有情况下。