C++ 虚拟模板方法
我有一个抽象类(我知道它不会以这种方式编译,但它是为了理解我想要做什么):
I have an abstract class (I know that it will not compile this way, but it's for comprehension of what I want to do) :
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
标识的双精度(内部机制不是这里的主要问题)设置为双数据.
So when I call setData<double>("foodouble", data)
I want the double identified by foodouble
(internal mechanism which is not the main concern here) to be set to the double data.
那怎么做呢?
我认为输入类似 virtual void setData
之类的内容可能是一种意思,但我不知道该怎么做.
I think that there may be a mean by typing something like virtual void setData<double>(std::string id, double data)
but I don't know how to do it.
推荐答案
问题是你不能轻易地将静态时间多态(模板)和运行时多态混合在一起.该语言不允许您的示例中的特定构造的原因是,可能有无限种不同的类型可以实例化您的模板成员函数,这反过来意味着编译器必须生成代码来动态分派这些许多类型,这是不可行的.
The problem is that you cannot mix static time polymorphism (templates) with runtime polymorphism easily. The reason for the language disallowing the particular construct in your example is that there are potentially infinite different types that could be instantiating your template member function, and that in turn means that the compiler would have to generate code to dynamically dispatch those many types, which is infeasible.
这里可以做不同的事情来绕过这个限制,基本上要么去掉静态多态,要么去掉动态多态.从方程中删除动态多态性可以通过提供一个不是派生的类型来存储
映射,然后提供仅在基本级别解析它的模板:
There are different things that can be done here to get around the limitation, basically either take away the static or the dynamic polymorphism. Removing dynamic polymorphism from the equation could be done by providing a type that is not derived from, to store the <key,value>
mappings, and then offering the template that resolves that only at the base level:
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
中实现功能来完成,但分离关注点可能是有意义的)
Now deriving classes can access the ValueStore
from the base and there is no need for polymorphism. (This can also be done by implementing the functionality directly in AbstractComputation
but it probably makes sense to separate concerns)
另一种选择是保持运行时多态性,但移除静态多态性.这可以通过在基类上执行类型擦除然后分派到采用 类型擦除 参数的适当(非模板化)函数来完成.最简单的版本就是使用 boost::any
:
The other option is to maintain runtime polymorphism, but remove static polymorphism. This can be done by performing type erasure on the base class and then dispatching to the appropriate (non-templated) function that takes the type-erased arguments. The simplest version of this is just using 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
是一个具体的(非模板化的)类型,可以存储任何类型在内部通过对参数使用类型擦除,同时允许对数据进行类型安全的检索.
How type erasure is implemented under the hood is interesting, but out of the scope here, the important part is that a boost::any
is a concrete (non-templated) type that can store any type internally by using type erasure on the arguments, and at the same time allows for type-safe retrieval of the data.
相关文章