У меня есть набор классов, которые используются для подготовки данных для сериализации. Все они являются производными от базового класса cBase
, который не имеет ничего общего с вопросом.
Среди производных классов есть:
class cValue: public cBase
{
public:
cValue(){}
template< class T > void set( const T & value ){ data_ = value; }
protected:
QVariant data_;
};
Это класс для хранения простых значений, таких как строка или число. А вот класс для представления объекта (в основном то, что может содержать пары «имя-значение»):
class cObject: public cBase
{
public:
cObject(){}
void addAttribure( const QString & name, cBase * value )
{
if( attributes_.contains( name ) )
delete attributes_[name];
attributes_[name] = value;
}
template< class T > void addAttribure( const QString & name, const T & value )
{
cValue * tmp = new cValue();
tmp->set( value );
addAttribure( name, tmp );
}
protected:
QMap< QString, cBase * > attributes_;
};
Цель этого состоит в том, чтобы иметь возможность добавлять атрибуты как с уже созданными объектами: addAttribute(someName, someObject);
и с необработанными значениями: addAttribute("name", 42);
Теперь этот код компилируется. Однако, если я попытаюсь создать объект, подобный этому:
cValue *tmp = new cValue();
tmp->set( 42 );
cObject obj;
obj.addAttribure("The Answer", tmp);
Я получаю следующую ошибку:
/usr/include/qt4/QtCore/qvariant.h:429:12: error: 'QVariant::QVariant(void*)' is private
../../source/private/../include/MyClasses.h:36:51: error: within this context
Ошибка появляется в строке, где cValue
«s set()
функция объявлена.
Теперь, если я удалю шаблонную версию addAttribute()
и поместите точно такой же код из этой функции в мой основной:
cObject obj;
cValue * tmp = new cValue();
tmp->set( 42 );
obj.addAttribure( "The Answer", tmp );
это работает отлично. Я полагаю, что это как-то связано с тем, что оба addAttribute()
а также set()
функции являются шаблонными, но я не понимаю, как решить эту проблему, или, по крайней мере, как обойти это.
Заметка: если возможно, я бы хотел не сделать сами классы шаблонными, только функции.
Проблема в том, что вы ожидаете, что компилятор вызовет addAttribure(const QString& name, cBase* value)
когда используешь cValue
, так как cValue
происходит от cBase
, Но так как они не совпадают точно, компилятор вызывает addAttribure<cValue*>(const QString& name, const cValue* value)
вместо.
Вот почему (как отмечено в вашем комментарии) звонит addAttribure(name, static_cast<cBase*>(tmp))
работал.
Проблема и причина, по которой ваше исправление с помощью приведения работает, заключается в том, что компилятор выбирает функцию без шаблонов только тогда, когда вы вызываете ее именно с типами параметров ее сигнатуры. В этом случае вы не используете cBase*
, но cObject*
, Правда, последний может быть автоматически преобразован в первый, но компилятор видит, что он может создать экземпляр шаблона для создания функции, которая точно соответствует параметру, поэтому он выбирает это.
Вы можете пойти со своим актером:
addAttribure( name, static_cast<cBase *>(tmp) );
или вы можете использовать указатель базового класса напрямую, чтобы избежать приведения:
cBase* pBase = tmp;
addAttribure( name, pBase );
Возможно, есть проблема с идентификацией типа. У меня была похожая проблема с QT, но некоторое время назад. Может тебе стоит попробовать
template< class T > void set( const T & value )
{
data_ = QVariant::fromValue( value );
// or data_.setValue( value )
}
Это может быть как-то связано с этим:
Я смутно помню, как мои собственные шаблонные функции-члены не компилировались до того, как я явно квалифицировал их как таковые.