我看到迭代器、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()) {
^
-
您没有修改列表,因此使用const引用。您也不需要担心容器的确切类型。任何STL兼容的容器都可以。
-
使用
std::is_same
而不是typeid
。 -
textStream
类成员始终使用filePerson
文件。pFile
从不用于任何用途。这很可能是个bug。 -
使用现有文件是不正确的——你基本上是将其用于文件名存储,而且如果保存失败,它不会确保数据不会被损坏。请改用
QSaveFile
。 -
该文件存储文本数据,必须以文本模式打开。
正确的实现如下所示-注意完整的签名。
#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();
}
不能在变量声明中使用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或更高版本,请考虑使用基于范围的for
循环,这样您就根本不必处理迭代器:
// 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();
}
或者,您可以使用Qt自己的foreach
扩展:
// 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)