Передать тип возвращаемого значения для шаблонной функции из switch ? ( в вопросе сложночитаемый код)

Вступление: Есть public метод OpenFile со следующей сигнатурой:

static bool OpenFile(QString filePath,FileType fTtpe,DataContainerType containerT,QIODevice::OpenModeFlag rwFlag=QIODevice::ReadWrite);

Помимо всего прочего, в него передается элемент перечисления DataContainerType, следующего вида:

enum DataContainerType
{
    QStringListContainer,
    QMapContainer,
    ListOfListContaineer
};

Внутри OpenFile - вызывается шаблонный метод readData:

template<typename retT,typename containerCastClass,typename castedClassType, typename obj_class, typename obj, typename ...args>
    static retT readData( containerCastClass c,castedClassType c1,obj_class cl, obj o,args... ar);

Подробнее, про написание этого метода, я задавал отдельный вопрос

Пример его вызова:

   readData<QStringList>(static_cast<QStringList(QVariant::*)() const>(&QVariant::toStringList),
                              static_cast<void(QStringList::*)(const QList<QString> &t)>(&QStringList::append),
                              static_cast< QByteArray ( QIODevice:: * )(qint64 maxSize) >(&QFile::readLine),
                              currentOpenTxt,
                              qint64{0});

Собственно, основная работа метода, не учитывая дополнительных проверок:

auto read{
        [&]()->auto{
            static auto castedContainer  =  std::invoke(c, currentContainer);// convert QVariant to QStringList, QMap..
            qDebug()<<typeid (castedContainer).raw_name();
            QString readedData=std::invoke(cl,o,ar...); //read line from txt, row/column from xlsx
            std::invoke(c1,castedContainer,retT({readedData}));//append, insert...
            return castedContainer;
        }
    };

Суть вопроса: Как, в зависимости от DataContainerType - задать тип для параметра возвращаемого значения, не дублируя код?

Поясню:

Как, вместо этого:

switch (containerT) {
    case DataContainerType::QStringListContainer:
        
        readData<QStringList>(static_cast<QStringList(QVariant::*)() const>(&QVariant::toStringList),
                              static_cast<void(QStringList::*)(const QList<QString> &t)>(&QStringList::append),
                              static_cast< QByteArray ( QIODevice:: * )(qint64 maxSize) >(&QFile::readLine),
                              currentOpenTxt,
                              qint64{0});
        
        break;
    case DataContainerType::QMapContainer:
        
        readData<QMap<QString,QString>>(static_cast<QMap<QString,QString>(QVariant::*)() const>(&QVariant::toMap),
                              static_cast<QMap::iterator(QMap<QString,QString>::*)(const Key &key, const T &value)>(&QMap<QString,QString>::insert),
                              static_cast< QByteArray ( QIODevice:: * )(qint64 maxSize) >(&QFile::readLine),
                              currentOpenTxt,
                              qint64{0});
        
        break;
    case DataContainerType::ListOfListContaineer:
        
        readData<QList<QStringList>>(static_cast<QList<QVariant>(QVariant::*)() const>(&QVariant::toList),
                              static_cast<void(QList::*)(const QList<QString> &t)>(&QList<QString>::append),
                              static_cast< QByteArray ( QIODevice:: * )(qint64 maxSize) >(&QFile::readLine),
                              currentOpenTxt,
                              qint64{0});
        
        break;
    }

Сделать что-то вроде: (псевдокод)

  auto _type;
    auto _toContainer;
    auto containerOperation;
    
    switch (containerT) {
    case DataContainerType::QStringListContainer:
        _type=&QStringList;
        _toContainer=static_cast<QStringList(QVariant::*)() const>(&QVariant::toStringList);
        containerOperation=static_cast<void(QStringList::*)(const QList<QString> &t)>(&QStringList::append);
        break;
    case DataContainerType::QMapContainer:
          _type=&QMap<QString,QString>;
          _toContainer=static_cast<QMap<QString,QString>(QVariant::*)() const>(&QVariant::toMap);
          containerOperation=static_cast<QMap::iterator(QMap<QString,QString>::*)(const Key &key, const T &value)>(&QMap<QString,QString>::insert);
        break;
    case DataContainerType::ListOfListContaineer:
          _type=&QList<QString>
            _toContainer=static_cast<QList<QVariant>(QVariant::*)() const>(&QVariant::toList);
          containerOperation=    static_cast<void(QList::*)(const QList<QString> &t)>(&QList<QString>::append);
        break;
    }
    


readData<_type>(_toContainer,
                                  containerOperation,
                                  static_cast< QByteArray ( QIODevice:: * )(qint64 maxSize) >(&QFile::readLine),
                                  currentOpenTxt,
                                  qint64{0});

Зачем все это нужно!?

У меня работа метода по сути зависит от двух параметров - тип читаемого файла и тип принимающего контейнера. Так вот, что бы не проверять каждый из 3-х типов контейнеров, для каждого из 3-х (возможно в будущем - больше) типов файлов (понятно, что выполнится одно ветка, но мы говорим про объемы кода и нецелесообразность его дублирования) - хотелось бы вынести эту проверку до проверки типа файла.


Ответы (1 шт):

Автор решения: Sheridan

Я, конечно, не знаю задачи и проекта вообще, но тут я бы реализовал набор классов: базовый (основной функционал и виртуальный метод чтения данных) и Х наследников, в которых виртуальный метод определён.

→ Ссылка