0

Following up on a great answer, I am trying to get around an -apparanently common- error **C2536 : cannot specify explicit initializer for arrays** for line in line: QLineEdit * edits[3] = {&lineEditName, &lineEditGender, &lineEditRegion};

I have read other solutions (e.g. 1, 2) but do not appear to apply in my case. I am using Qt Creator 4.1.0 with Qt 5.7.0, MSVC 2013 in Windows with C++. Any suggestions are welcome.

On an extra note, and in the interest of better understanding Qt with C++, could someone point to a different way -instead of using arrays- for holding the new parsed json results?

Below you can see the full code from that answer (the line in question is in mainwindow.h):

main.cpp

// https://github.com/KubaO/stackoverflown/tree/master/questions/into-mainwin-39643510
#include "mainwindow.h"
#include "controller.h"

int main(int argc, char *argv[])
{
   QApplication app{argc, argv};
   MainWindow ui;
   Controller ctl;
   QTimer timer;
   timer.start(5*1000);
   QObject::connect(&timer, &QTimer::timeout, &ctl, &Controller::get);

   QObject::connect(&ctl, &Controller::busy, &ui, [&]{ ui.setState(MainWindow::Loading); });
   QObject::connect(&ui, &MainWindow::request, &ctl, &Controller::get);
   QObject::connect(&ctl, &Controller::error, &ui, [&]{ ui.setState(MainWindow::Error); });
   QObject::connect(&ctl, &Controller::values, &ui, &MainWindow::setFields);
   ui.show();
   return app.exec();

controller.h

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QtNetwork>

class Controller : public QObject {
   Q_OBJECT
   QNetworkAccessManager manager{this};
   QNetworkRequest request;
   Q_SLOT void onReply(QNetworkReply *);
public:
   explicit Controller(QObject * parent = nullptr);
   Q_SLOT void get();
   Q_SIGNAL void busy();
   Q_SIGNAL void error(const QString &);
   Q_SIGNAL void values(const QString & name, const QString & gender, const QString & region);
};

#endif // CONTROLLER_H

controller.cpp

#include "controller.h"

Controller::Controller(QObject *parent) : QObject(parent)
{
   QUrlQuery query;
   query.addQueryItem("amount", "1");
   query.addQueryItem("region", "United States");
   QUrl url("http://uinames.com/api/");
   url.setQuery(query);
   request = QNetworkRequest(url);
   connect(&manager, &QNetworkAccessManager::finished, this, &Controller::onReply);
}

void Controller::onReply(QNetworkReply * reply) {
   if (reply->error() != QNetworkReply::NoError) {
      emit error(reply->errorString());
      manager.clearAccessCache();
   } else {
      //parse the reply JSON and display result in the UI
      auto jsonObject = QJsonDocument::fromJson(reply->readAll()).object();
      auto fullName = jsonObject["name"].toString();
      fullName.append(" ");
      fullName.append(jsonObject["surname"].toString());
      emit values(fullName, jsonObject["gender"].toString(), jsonObject["region"].toString());
   }
   reply->deleteLater();
}

void Controller::get() {
   emit busy();
   manager.get(request);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

class MainWindow : public QWidget {
  Q_OBJECT
  QFormLayout layout{this};
  QLineEdit lineEditName;
  QLineEdit lineEditGender;
  QLineEdit lineEditRegion;
  QPushButton button{"Get Name"};
  QLineEdit * edits[3] = {&lineEditName, &lineEditGender, &lineEditRegion};
public:
  enum State { Normal, Loading, Error };
  explicit MainWindow(QWidget * parent = nullptr);
  Q_SLOT void setFields(const QString & name, const QString & gender, const QString & region);
  Q_SLOT void setState(State);
  Q_SIGNAL void request();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
   for(auto edit : edits) edit->setReadOnly(true);
   layout.addRow("Name:", &lineEditName);
   layout.addRow("Gender:", &lineEditGender);
   layout.addRow("Region:", &lineEditRegion);
   layout.addRow(&button);
   connect(&button, &QPushButton::clicked, this, &MainWindow::request);
}

void MainWindow::setFields(const QString & name, const QString & gender, const QString & region) {
   setState(Normal);
   lineEditName.setText(name);
   lineEditGender.setText(gender);
   lineEditRegion.setText(region);
}

void MainWindow::setState(MainWindow::State state) {
   if (state == Normal) {
      for (auto edit : edits) edit->setEnabled(true);
      button.setEnabled(true);
   }
   else if (state == Loading) {
      for (auto edit : edits) edit->setEnabled(false);
      button.setEnabled(false);
   }
   else if (state == Error) {
      for (auto edit : edits) edit->setText("Error...");
      button.setEnabled(true);
   }
}
Community
  • 1
  • 1
  • What if: QLineEdit * edits[] {&lineEditName, &lineEditGender, &lineEditRegion}; – Alexander V Sep 27 '16 at 22:07
  • @AlexanderVX No doesn't solve it either, it gives the same error along with `an array of unknown size cannot be used in a range-based for statement`. Any other suggestions or provide an alternative for the `edits` array altogether? –  Sep 28 '16 at 07:10

1 Answers1

1

The problem is that MSVC2013 does not support all C++11 features. The main issue here, is that you can't specify in-class initialization for member arrays.

The closest workaround in my opinion would be to use an std::array instead of the C array for edits, since MSVC2013 seems to support initializing an std::array using aggregate initialization, you can replace your:

QLineEdit * edits[3] = {&lineEditName, &lineEditGender, &lineEditRegion};

to use std::array and aggregate initialization like this:

std::array<QLineEdit*,3> edits{{&lineEditName, &lineEditGender, &lineEditRegion}};

Note that you have to add #include <array> to your mainwindow.h to use std::array.

On an extra note, and in the interest of better understanding Qt with C++, could someone point to a different way -instead of using arrays- for holding the new parsed json results?

You are not using arrays for holding the new parsed json results, this is just how you use QJsonObject.

If you are looking for a way to further separate JSON parsing in its own class. You might want to have some class (eg. NameData) that encapsulates the name's data (fullName, gender, region), and provides a way to be constructed out of a QByteArray of JSON data.

This way the Controller class does not know anything about JSON, it just uses the NameData class to parse the reply it has from the network.

you may implement it like this:

namedata.h

#ifndef NAMEDATA_H
#define NAMEDATA_H

#include <QtCore>

class NameData
{
public:
    QString fullName;
    QString gender;
    QString region;

    static NameData fromReplyByteArray(QByteArray byteArray);
};

#endif // NAMEDATA_H

namedata.cpp

#include "namedata.h"

NameData NameData::fromReplyByteArray(QByteArray byteArray){
    QJsonObject jsonObject = QJsonDocument::fromJson(byteArray).object();
    NameData result;
    result.fullName = jsonObject["name"].toString();
    result.fullName.append(" ");
    result.fullName.append(jsonObject["surname"].toString());
    result.gender= jsonObject["gender"].toString();
    result.region= jsonObject["region"].toString();
    return result;
}

Now, the onReply function in Controller class, should be:

void Controller::onReply(QNetworkReply * reply) {
    if (reply->error() != QNetworkReply::NoError) {
        emit error(reply->errorString());
        manager.clearAccessCache();
    } else {
        //parse the reply JSON and display result in the UI (using the separate class)
        NameData nameData= NameData::fromReplyByteArray(reply->readAll());
        emit values(nameData.fullName, nameData.gender, nameData.region);
    }
    reply->deleteLater();
}
Mike
  • 8,055
  • 1
  • 30
  • 44