Универсальный вызов методов различных классов через указатель на функцию?
Есть метод ReadData, который должен работать с тремя типами файлов: txt, accdb, xlsx.
Проблема заключается в том, что передаваемые в него файлы, имеют очень большой объем - точно более милионна записей. Поэтому, приходится читать отдельными блоками.
Вся "логика" проверки размера блоков и.т.д, которая содержится в этом методе - по-сути одинакова для всех трех типов файлов. Разница сотстоит только в том, что в случае текстового файла чтение выполняется с помощью метода readLine, для эксель-файла - метод readRow (я использую библиотеку QXlsx), для accdb - результат sql запроса. Причем, чтение выполняется (что логично) в цикле и вынести как-то логику проверок в отдельный метод, пока что мне - не представляется возможным.
Чего я хочу добиться:
Я хочу, что бы в метод можно было, с помощью шаблонов и кортежей передавать - передавать нужный объект и указатель на метод этого объекта, который необходимо вызывать. Вот, как сейчас выглядит сигнатура этого метода:
template<class T, class D,class... K>
static QStringList* readData(T& t, D (T::*f)(K... ));
-вариант с таким вызовом взял из этого ответа:
https://ru.stackoverflow.com/a/632158/203448
template<class T> void callf(T& t, void (T::*f)()) { (t.*f)(); } int main() { A1 a; B1 b; callf(a,&A1::show); callf(b,&B1::show); return 0; }
Предполагается, что метод будет вызывать следующие методы внутри себя (т.е в качестве
D (T::*f)(K... ) - будут передаваться:)
QByteArray readLine(qint64 maxlen = 0);QVariant Document::read(int row, int col) const
(или его перегрузка QVariant Document::read(const CellReference &cell) const)
- Для accdb файл еще не продумал
Т.е, для текстового файла это будет:
readData<QFile,QByteArray,long long>(*currentOpenTxt,&QFile::readLine)
- и этот вариант замечательно работает на практике - вот его вызов:
while (!currentOpenTxt->atEnd()) {
tmpReadContainer.append((t.*f)(0));
}
(пока что, для упрощения, я оставил здесь !currentOpenTxt->atEnd(), но позже, тооже буду думать над метом-оберткой.)
Проблема возникает, когда я пытаюсь сделать тоже самое для метода QVariant Document::read(int row, int col) const - вот так:
readData<QXlsx::Document,QVariant,const QXlsx::CellReference&>
(*xlsxR,&QXlsx::Document::read)
И получаю следующую ошибку:
no matching function for call to 'FileOpenClass::readData<QXlsx::Document, QVariant, QXlsx::CellReference>(QXlsx::Document&, )' insertData( readDataQXlsx::Document,QVariant,QXlsx::CellReference(*xlsxR,&QXlsx::Document::read));
- т.е, категорически не хочет воспринимать QVariant как тип для шаблона.
Вторая проблема состоит в том, что в качестве параметров метода, я использую кортеж
D (T::*f)(K... k)
, но при вызове метода: tmpReadContainer.append((t.*f)(k...)); - не могу обратиться к нему подобным образом
(поэтому, оставил пока что в коде: tmpReadContainer.append((t.*f)(0)); - т.к тестировал только для readLine метода)
Вот полный код метода readData:
QStringList* FileOpenClass::readData(T& t, D (T::*f)(K... k))
{
tmpReadContainer.clear();
txtFileRowsCount=countTxtLines();
if (txtFileRowsCount<maxRowsCount) {
//currentOpenTxt->seek(0);
while (!currentOpenTxt->atEnd()) {
tmpReadContainer.append((t.*f)(0)); // чтение разных файлов здесь
}
}
else {
static bool firstRead=true;
static int blockCount=1;
static int blockSize=0;
static int alreadyReadBlock=0;
static bool tailWrote=false;
while(!tailWrote)
{
if (allReadFlag) {
//tail
blockSize=txtFileRowsCount-alreadyReadBlock*blockSize;
for (int var = 0; var < blockSize; ++var) {
tmpReadContainer.append((t.*f)(0));//здесь
}
tailWrote=true;
}
else
{
while(!allReadFlag)
{
if (firstRead) {
currentOpenTxt->seek(0);
while (txtFileRowsCount%blockCount==0) {
blockCount++;
}
blockSize =txtFileRowsCount/blockCount;
firstRead=false;
qDebug()<<blockSize<<endl;
}
//first read end
else
{
//read block
for (int var = 0; var < blockSize; ++var) {
tmpReadContainer.append((t.*f)(0)); // и здесь
}
alreadyReadBlock++;
if (alreadyReadBlock==blockCount) {
allReadFlag=true;
}
if (txtFileRowsCount%blockSize==0) {
tailWrote=true;
}
}
}
}
}
}
//qDebug()<<tmpReadContainer.size();
return &tmpReadContainer;
}
Ряд вопросов:
Как можно обойти проблему с QVariant в качесиве типа для шаблона?
Как правильно обратиться к кортежу в данном случае?
Более общие вопросы:
Как лучше переписать/изменить код в подобной ситуации - тюе когда имеется почти одиаковый код и не хочется иметь три практически идентиных метода?
Посоветуйте, что почитать/посмотреть про написание "универсального и гибкого" кода (обращаю вгимание, что в " " - т.к понимаю, что не существует "серебряной пули", этот вопрос скорее про техники/методологмм/подходы - ведь должны же такие существовать?)