Проблема в том, что вы не можете легко смешать статический полиморфизм времени (шаблоны) с полиморфизмом времени исполнения.Причина, по которой язык запрещает конкретную конструкцию в вашем примере, состоит в том, что существуют потенциально бесконечные различные типы, которые могут быть экземплярами вашей функции-члена шаблона, и это, в свою очередь, означает, что компилятору придется генерировать код для динамической отправки этих многих типов,невыполнимо.
Есть разные вещи, которые можно сделать здесь, чтобы обойти ограничение, в основном либо убрать статический или динамический полиморфизм.Удаление динамического полиморфизма из уравнения может быть выполнено путем предоставления типа, который не является производным от, для хранения отображений <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
, но, вероятно, имеет смысл разделить проблемы)
Другой вариант - сохранить полиморфизм во время выполнения, но удалить статический полиморфизм.Это можно сделать, выполнив стирание типа в базовом классе, а затем отправив соответствующую (не шаблонную) функцию, которая принимает тип-стертые аргументы.Простейшая версия этого просто использует 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
являетсяконкретный (не шаблонный) тип, который может внутренне хранить любой тип, используя стирание типов в аргументах, и в то же время позволяет безопасно извлекать данные из типов.