2009-06-09 7 views
0

je le code suivant:C++ héritage Qt problème QSTRING

template <class T> 
bool loadCSV (const QString &filename, map<T,int> &mapping){ 
    QFile boxfile; 
    boxfile.setFileName(filename); 
    QString line; 
    QStringList list; 

    if (!boxfile.open(QIODevice::ReadOnly)){ 
     cout << "Could not open box data file." << endl; 
     return false; 
    } 

    QTextStream stream2(&boxfile); 

    while (!stream2.atEnd()){ 
     line = stream2.readLine(); 
     list = line.split(','); 
     mapping[list.front().toInt()]=list.back().toInt();  
    } 

    return true; 
} 

Il faut un fichier CSV et il colle en:

map<int, int> mapping 
Structure

. Maintenant, ceci est fait comme un modèle de sorte que je puisse également utiliser pour coller des données dans une structure. Maintenant, pour ce faire, la dernière ligne de la boucle while doit être modifiée et je ne suis pas sûr de la meilleure façon d'y parvenir.

je pouvais penser à quelques façons:

  1. certains comment détecter le type et avoir une sorte de ligne conditionnelle là-bas (je ne suis pas vraiment sûr si cela est possible et si oui comment faire . ce

  2. ajouter une fonction de classe à QStringList pour ce faire

J'ai essayé l'option 2 et ai fait.

void QStringList::cInsert(map<int,int> &mapping){ 
    mapping[this->front().toInt()]=this->back().toInt(); 
} 

void QStringList::cInsert(map<string,int> &mapping){ 
    mapping[(this->front()).toAscii()]=this->back().toInt(); 
} 

Cela ne fonctionnait pas car j'avais également besoin de définir ces fonctions dans la classe QStringList et cela devenait donc un peu compliqué. Au lieu. J'essaie d'hériter de QStringList:

class myQStringList: public QStringList{ 
    public: 
     void cInsert(map<int,int> &mapping); 
     void cInsert(map<string,int> &mapping); 
}; 

void myQStringList::cInsert(map<int,int> &mapping){ 
    mapping[this->front().toInt()]=this->back().toInt(); 
} 

void myQStringList::cInsert(map<string,int> &mapping){ 
    mapping[(this->front()).toAscii()]=this->back().toInt(); 
} 

puis modifiez le code:

template <class T> 
bool loadCSV (const QString &filename, map<T,int> &mapping){ 
    QFile boxfile; 
    boxfile.setFileName(filename); 
    QString line; 
    myQStringList list; 

if (!boxfile.open(QIODevice::ReadOnly)){ 
    cout << "Could not open box data file." << endl; 
    return false; 
} 

QTextStream stream2(&boxfile); 

while (!stream2.atEnd()){ 
    line = stream2.readLine(); 
    list = line.split(','); 
     list.cInsert(mapping); 
} 

return true;} 

MAIS. Je reçois une erreur par rapport à l'affectation line.split/liste:

main.cpp:123: error: no match for 'operator=' in 'list = QString::split(const QChar&, QString::SplitBehavior, Qt::CaseSensitivity) const(((const QChar&)(&QChar(44))), KeepEmptyParts, CaseSensitive)' 

Je ne suis pas sûr de ce que cette erreur et ne sais pas si elle est de faire avec l'opérateur assign/copie ne pas être hérité?

Et par rapport à la nouvelle classe réelle, je reçois cette erreur:

main.cpp:104: error: no match for 'operator[]' in 'mapping[QString::toAscii() const()]' 
c:/qt/mingw/bin/../lib/gcc/mingw32/3.4.2/../../../../include/c++/3.4.2/bits/stl_map.h:332: note: candidates are: _Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = std::string, _Tp = int, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, int> >] 
main.cpp: In function `bool loadCSV(const QString&, std::map<T, int, std::less<_Key>, std::allocator<std::pair<const T,int> > >&) [with T = int]': 

Ce que je ne comprends tout simplement pas. Quelqu'un peut-il expliquer s'il vous plaît?

En outre, je ne suis pas sûr si la façon dont je vais à ce sujet est correcte et j'apprécierais des conseils par rapport à cela aussi. Merci.

Répondre

0

je résolu le problème en lançant explicitement:

list = (const myQStringList&) line.split(','); 
void myQStringList::cInsert(map<string,int> &mapping){ 
    mapping[(string)(this->front()).toAscii()]=this->back().toInt(); 
} 
+0

Vous avez également la méthode QString :: toStdString(). Et QString :: fromStdString() aussi ... –

+0

N'oubliez pas d'accepter votre propre réponse! :) – ralphtheninja

+0

Un casting de style C dans un programme C++ est mauvais. Vous pouvez utiliser static_cast à la place .. ou dynamic, reinterpret et const_cast en fonction de vos objectifs. Avec qobject_cast et qvariant_cast dans un programme Qt C++. –

2

Je propose la conversion de type T QString à l'extérieur de votre fonction.Par conséquent, quelque chose comme:

template< typename T> 
struct converter { }; 

template<> 
struct converter< int> 
{ 
static int convert(const QString& source) 
{ 
    return source.toInt(); 
} 
}; 

template<> 
struct converter< std::string> 
{ 
static std::string convert(const QString& source) 
{ 
    return source.toStdString(); 
} 
}; 

template< typename T> 
T convertFromString(const QString& source) 
{ 
    return converter<T>::convert(source); 
} 

Ensuite, utilisez cette fonction de conversion dans votre boucle (intérieur tout):

Au lieu de

mapping[list.front().toInt()]=list.back().toInt(); 

écrire:

mapping[ convert<T>(list.front())]=list.back().toInt(); 

Note: Le convertisseur de classe (un nd ses deux spécialisations) sont définis de sorte que la fonction de conversion peut être utilisée comme une fonction de modèle (similaire à static_cast ou à boost :: lexical_cast si vous le souhaitez).

Je n'ai pas essayé de compiler le code. C'est juste une idée.

1

En ce qui concerne les fichiers CSV, Qt fournit des fonctionnalités précises via la fonction QString :: section. Donc, pour trouver des colonnes nécessaires je traite l'en-tête comme suit:

int AmountInd = (line.left(line.indexOf("Amount")).count(','); 

pour obtenir l'indice de cette colonne. Ensuite, pour les lignes à venir j'extraire la sous-chaîne de cette colonne:

QString AmountStr = (line.section(',', AmountInd, AmountInd); 
double Amount = AmountStr.toDouble(); 

espérons que vous trouverez la fonction de section ;-)

USEFULL