我有一个抽象类(我知道它不会这样编译,但它是为了理解我想做的事情):
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)
我想要由 foodouble
标识的双重身份(这里不是主要关注的内部机制)设置为双数据。
那该怎么做呢?
我认为键入 virtual void setData<double>(std::string id, double data)
之类的内容可能是一种意思。但我不知道该怎么做。
最佳答案
问题是您不能轻易地将静态时间多态性(模板)与运行时多态性混合在一起。语言不允许您的示例中的特定构造的原因是,可能有无限种不同的类型可以实例化您的模板成员函数,这反过来意味着编译器必须生成代码来动态调度这些类型,这是不可行的。
这里可以做不同的事情来绕过这个限制,基本上要么去掉静态多态性,要么去掉动态多态性。从方程中删除动态多态性可以通过提供一个不是派生自的类型来存储<key,value>
。映射,然后提供仅在基础级别解决该问题的模板:
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
中实现功能来完成,但分离关注点可能是有意义的)
另一种选择是保持运行时多态性,但删除静态多态性。这可以通过对基类执行类型删除,然后分派(dispatch)到采用 type-erased 参数的适当(非模板化)函数来完成。最简单的版本就是使用 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;
};
类型删除是如何在幕后实现的很有趣,但是超出了这里的范围,重要的部分是 boost::any
是一种具体(非模板化)类型,可以通过在参数上使用类型删除在内部存储 任何 类型,同时允许对数据进行类型安全的检索。
关于C++ 虚拟模板方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7968023/