(typedef) итератор typename не работает в c ++, qt - PullRequest
0 голосов
/ 01 июня 2018

Я видел уже много решенных проблем с итераторами и typedef и typename.Ни один из ответов не помог мне.

Я уже пытался без чего-либо и

typename QLinkedList<T>::iterator iter = TList->begin();

и

typedef typename QLinkedList<T>::iterator iter = TList->begin();

весь шаблон:

template <class T>
void DataManager::saveObject(QLinkedList<T> * TList) {
    QFile * pFile;
    // choose a file in case of class
    if( typeid(T) == typeid(Medium) ) pFile = &fileMedium;
    else                              pFile = &filePerson;
    // open the choosen file
    pFile->open(QIODevice::WriteOnly | QIODevice::Truncate);
    // open the textSteam to write
    textStream.setDevice(&filePerson);
    // write each information to the textstream/file
    if(!TList->isEmpty())
        // set iterator                         
        typename QLinkedList<T>::iterator iter = TList->begin();
        while(iter != TList->end()) {    // <--- Err: not declared !
            textStream << iter->getDataInCSV();
            ++iter; //move iterator to next
        }
   // close the file
   pFile->close();
}

ошибка:

    error: 'iter' was not declared in this scope
     while(iter != TList->end()) {
           ^

Ответы [ 2 ]

0 голосов
/ 01 июня 2018
  1. Вы не изменяете список - поэтому возьмите его с помощью константной ссылки.Вам также не нужно беспокоиться о точном типе контейнера.Подойдет любой STL-совместимый контейнер.

  2. Используйте std::is_same вместо typeid.

  3. Член класса textStream всегда используетфайл filePerson.pFile никогда не используется ни для чего.Скорее всего, это ошибка.

  4. Нельзя использовать существующий файл - вы по существу используете его для хранения имени файла, и это не гарантирует, что данные не будут поврежденыесли сбой не удастсяВместо этого используйте QSaveFile.

  5. Файл хранит текстовые данные и должен быть открыт в текстовом режиме.

Правильная реализация будет выглядеть следующим образом- отметьте полную подпись.

#include <type_traits>

// Returns true upon success, false upon failure
template <class T> bool DataManager::saveObject(const T& data) const {
   using value_type = typename T::value_type;
   bool const isMedium = std::is_same<value_type, Medium>::value;
   bool const isPerson = std::is_same<value_type, Person>::value;
   static_assert(isMedium || isPerson,
            "The data must be of either Medium or Person type");
   const QFileDevice &aFile = isMedium ? fileMedium : filePerson;
   Q_ASSERT_X(!aFile.isOpen(), "saveObject", "The file must not be open");
   QSaveFile file(aFile.fileName());
   if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
      return false;
   {
      QTextStream stream(&file);
      for (auto &item : data)
         stream << item;
      stream.flush();
      if (stream.status() != QTextStream::Ok)
         return false;
   }
   return file.commit();
}
0 голосов
/ 01 июня 2018

Вы не можете использовать typedef в объявлении переменной.

Вам также не нужно использовать typename, так как вы не определяете тип, который зависит от другоготип, указанный в параметре шаблона.

Вы просто пытаетесь объявить переменную существующего типа, поэтому просто используйте этот тип как есть, например:

// use a const_iterator to avoid detach-ing the list while iterating...
QLinkedList<T>::const_iterator iter = TList->cbegin();

Или, если вы используете C ++ 11 или более позднюю версию, вы можете упростить это до следующего:

auto iter = TList->cbegin();

В любом случае вы получаете ошибку «не объявлено в этой области», потому что вы неУ вас есть пара скобок в вашем if блоке:

if(!TList->isEmpty())
{ // <-- add this!
    // set iterator                         
    QLinkedList<T>::const_iterator iter = TList->cbegin();
    // or: auto iter = TList->cbegin();
    while(iter != TList->cend()) {
        textStream << iter->getDataInCSV();
        ++iter; //move iterator to next
    }
} // <-- add this!

Без дополнительных скобок ваш исходный код функционально идентичен следующему:

if(!TList->isEmpty()) {
    // set iterator                         
    QLinkedList<T>::iterator iter = TList->begin();
}
while(iter != TList->end()) {    // <--- iter is not in scope here!
    textStream << iter->getDataInCSV();
    ++iter; //move iterator to next
}

Как видите,Цикл while не находится в теле оператора if, поэтому переменная iter действительно не находится в области видимости для цикла while.

Если вы используете C ++ 11 или новее, рассмотрите вариант использования loop-based for loop , основанного на ранжировании, тогда вам вообще не придется иметь дело с итератором:

// write each information to the textstream/file
for (const T &item : qAsConst(*TList)) {
    textStream << item.getDataInCSV();
}

Или:

// write each information to the textstream/file
for (const auto &item : qAsConst(*TList)) {
    textStream << item.getDataInCSV();
}

В качестве альтернативы вы можете использовать собственное расширение foreach Qt:

// write each information to the textstream/file
foreach (const T &item, *TList)
    textStream << item.getDataInCSV();

В дополнение к этому, контейнеры Qtреализовать семантику копирования при записи с помощью подсчета ссылок, чтобы их было очень эффективно передавать по значению, вам не нужно передавать их по указателю, например:

void DataManager::saveObject(QLinkedList<T> TList)

Хотя я, вероятно, мог бывместо этого использовалась ссылка const, так как это предпочтительный способ передачи объекта, который вы не собираетесь изменять:

void DataManager::saveObject(const QLinkedList<T> &TList)
...