問題描述
我有一個抽象類(我知道它不會以這種方式編譯,但它是為了理解我想要做什么):
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.
這篇關于C++ 虛擬模板方法的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!