我有一组用于为序列化准备数据的类。所有这些都来自基类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
的{{1}}函数的行上。
现在,如果我删除set()
的模板化版本,并将该函数中完全相同的代码放入我的主文件中:
addAttribute()
它工作正常。我认为这与cObject obj;
cValue * tmp = new cValue();
tmp->set( 42 );
obj.addAttribure( "The Answer", tmp );
和addAttribute()
函数都是模板化的事实有关,但我不明白如何解决这个问题,或者至少如何解决这个问题。
注意:如果可能的话,我想不让这些类本身模板化,只有函数。
答案 0 :(得分:2)
问题以及使用强制转换修复的原因是编译器仅在您使用其签名的参数类型调用它时才选择非模板化函数。在这种情况下,您没有使用cBase*
,而是cObject*
。是的,后者可以自动转换为前者,但编译器发现它可以实例化模板以创建一个与参数完全匹配的函数,因此它会选择它。
你可以选择你的演员:
addAttribure( name, static_cast<cBase *>(tmp) );
或者您可以直接使用基类指针来避免强制转换:
cBase* pBase = tmp;
addAttribure( name, pBase );
答案 1 :(得分:0)
可能识别类型存在问题。我在QT遇到了类似的问题,但前段时间。也许你应该试试
template< class T > void set( const T & value )
{
data_ = QVariant::fromValue( value );
// or data_.setValue( value )
}
答案 2 :(得分:0)
这可能与此有关:
我依旧记得我自己的成员模板函数没有编译之前我明确地对它们进行了限定。
答案 3 :(得分:0)
问题在于,您希望编译器在使用addAttribure(const QString& name, cBase* value)
时调用cValue
,因为cValue
来自cBase
。但由于它们不是完全匹配,编译器会调用addAttribure<cValue*>(const QString& name, const cValue* value)
。
这就是为什么(如你的评论中所述)调用addAttribure(name, static_cast<cBase*>(tmp))
。