QJsonValue is private? - c++

I am learning C++ and trying to make something. But I ran into an error and I am not sure what's up. I am trying to create a simple thing that would accept an array, and turn it into JSON. But I'm getting an error
'QJsonValue::QJsonValue(const void*)' is private
within this context
file
#include "LoginDialog.h"
#include "ui_LoginDialog.h"
LoginDialog::LoginDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::LoginDialog)
{
setWindowFlags(Qt::FramelessWindowHint);
ui->setupUi(this);
}
LoginDialog::~LoginDialog()
{
delete ui;
}
void LoginDialog::set_socket(Socket *socket)
{
socket = socket;
QJsonArray data;
data.prepend("Hello");
socket->sendData(data);
}
void LoginDialog::on_minimize_clicked()
{
setWindowState(Qt::WindowMinimized);
}
void LoginDialog::on_quit_clicked()
{
exit(1);
}
accepting function
void Socket::sendData(QJsonArray data)
{
qDebug() << data[1];
}

Your problem is here:
data.prepend("Hello");
The prepend member function takes in a QJsonValue, which happens to have many constructors. Passing in a const char* makes it ambiguous as to which one you are referring to. C++ compilers will resolve this to a bool before they would resolve it to a QString. To combat this, the author of QJsonValue did this:
private:
// avoid implicit conversions from char* to bool
inline QJsonValue(const void*) {}
In any event, you can fix this problem by being more explicit:
data.prepend(QStringLiteral("Hello")); // Qt 5
data.prepend(QLatin1String("Hello")); // Qt 4, Latin1 string
data.prepend(QString("Hello")); // Qt 4, non-Latin1 string
Look here for more information about QStringLiteral.

Related

Storing a std::function as a private member results in it being null when used

I am at a loss for why this isn't working. I've tried passing a function by value, by reference, and still when I go to call the function from within SetFromState, it is null.
My class:
StateIndicator::StateIndicator(QWidget *parent) {
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy);
}
StateIndicator::StateIndicator(QWidget *parent,
const std::function<std::string (State)>& selectionStrategy)
:QWidget(parent),
selection_strategy_(selectionStrategy)
{
wrapped = new QLabel(this);
}
void StateIndicator::SetFromState(State state)
{
std::string resourcePath = selection_strategy_(state);
wrapped->setTextFormat(Qt::TextFormat::RichText);
char* buffer = new char[StateIndicator::label_format.length() + resourcePath .length()];
sprintf(buffer, label_format.c_str(), resourcePath .c_str());
wrapped->setText(buffer);
}
std::string TruckStateIndicator::DefaultSelectionStrategy(State state){
return ":img/Disconnected";
}
call:
StateIndicator* state = new StateIndicator(this);
ui->leftPaneLayout->insertWidget(1,state);
state->SetFromState(State::Connected);
When I use the debugger, in my constructor it shows that my selection strategy is set. But when I get to the call to SetFromState the private member selection_strategy_ is null.
However, my code works if within the SetFromState function I instead change it to:
std::function<std::string(TruckState)> strategy = &DefaultSelectionStrategy;
std::string path = strategy(state);
and assign the variable right there. It feels like something is going out of scope and causing my function pointer to become null, but I'm pretty much stuck.
Edited:
Here is the header file. I will also try to make the example minimal by removing the inheritance and trying to reproduce
#ifndef STATEINDICATOR_H
#define STATEINDICATOR_H
#include <QLabel>
#include "src/models/state.h"
class StateIndicator : public QWidget
{
public:
explicit StateIndicator(QWidget* parent);
explicit StateIndicator(QWidget* parent,
const std::function<std::string (State)>& selectionStrategy);
void SetFromState(State state);
private:
static std::string DefaultSelectionStrategy(State state);
QLabel* wrapped;
const std::function<std::string(State)> image_selection_strategy_;
inline const static std::string label_format = "<html><head/><body><p><"
"img src="%s"/>"
"</p></body></html>";
};
#endif // TRUCKSTATEINDICATOR_H
The problem was with how I was calling the overloaded constructor it seems:
StateIndicator::StateIndicator(QWidget *parent) {
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy);
}
should be
StateIndicator::StateIndicator(QWidget *parent) :
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy)
{
}

QT CPP How to solve ambiguous error when calling function?

I have a function for write data with using serial port.I am using the send function on several pages. I have not encountered such a problem before, but when I try to use it again on the same page, I get an error. When I try call function again I got
error: call of overloaded 'send(const char [6])' is ambiguous
here is my header file
#ifndef SETDATETIME_H
#define SETDATETIME_H
#include <QDialog>
#include <QTimer>
#include "serial.h"
namespace Ui {
class setdatetime;
}
class setdatetime : public QDialog
{
Q_OBJECT
public:
explicit setdatetime(QWidget *parent = nullptr);
~setdatetime();
void closeEvent(QCloseEvent *event);
public slots:
void curtime();
private slots:
void on_pushButton_clicked();
void on_detailSaveBtn_clicked();
private:
Ui::setdatetime *ui;
QTimer *timer;
Serial serialDateTime;
};
#endif // SETDATETIME_H
here is function I got error
void setdatetime::on_detailSaveBtn_clicked() {
QSerialPortInfo info;
QList<QSerialPortInfo> infoList = QSerialPortInfo::availablePorts();
foreach(info, infoList) QTextStream(stdout) << info.portName();
QString curport = info.portName();
if (!serialDateTime.isOpen()) {
if (serialDateTime.begin(QString(curport), 9600, 8, 0, 1, 0, false)) {
serialDateTime.send("HELLO"); // call to member function 'send' is ambiguous
serialDateTime.send(ui -> label -> text().toLatin1() + ui -> label_2 -> text().toLatin1()); //this working well
}
}
}
here is send function
bool Serial::send(QString message)
{
if (this->serialDevice->isOpen() && this->serialDevice->isWritable())
{
this->serialDevice->write(message.toStdString().c_str());
return true;
}
else
{
return false;
}
}
bool Serial::send(const QByteArray &message)
{
if (this->serialDevice->isOpen() && this->serialDevice->isWritable())
{
this->serialDevice->write(message);
return true;
}
else
{
return false;
}
}
How can I solve this issue ?
There is many meaning that warning can take. In your case, is say that your string litteral "HELLO" is a const char[6] but can be implicitly converted to a QByteArray or a QString.
The problem is that your compiler doesn't like that and prefer to know explicitly what to do.
You can either use the explicit keyword to prohibit implicit casting, or pass directly a QByteArray OR a QString explicitly converted to make your compiler know that you want to use one definition or the other.
serialDateTime.send(QByteArray::fromRawData("HELLO", 5)); // to call the QByteArray overload
serialDateTime.send(QString::fromUtf8("HELLO")); // to call the QString overload

While mocking with googletest, how to specify the argument type of an internal::AnythingMatcher for overloaded methods?

initial question
While testing with googletest, I use a mocked class, which contains an overloaded method, where one of the arguments differs in type.
This leads to an ambiguous function call when I do
EXPECT_CALL(mockedClass,mockedMethod(_,_)).WillOnce(Return(true));
I tried to combine the internal::AnythingMatcher underscore with a type specification by replacing the argument in question with An<type>(), TypedEq<type>(_), or Matcher<type>(_) as well as writing something like:
Matcher<type> customAnythingMatcher = _;
EXPECT_CALL(mockedClass,mockedMethod(_,customAnythingMatcher)).WillOnce(Return(true));
all to no avail.
Any hints how to disambiguate that call?
update #1
As requested, I elaborate by providing a minimal working -- or in this case a non-working -- example what I am trying to achieve:
myInterfaceToMock.h
#ifndef MYINTERFACETOMOCK_H
#define MYINTERFACETOMOCK_H
#include <QVariant>
#include <QtGlobal>
class MyInterfaceToMock {
virtual bool myMethod(QVariant &firstArgument,
const quint8 secondArgument) const = 0;
virtual bool myMethod(QByteArray &firstArgument,
const quint16 secondArgument) const = 0;
virtual bool myOtherMethod(quint8 firstAndOnlyArgument) const = 0;
};
#endif // MYINTERFACETOMOCK_H
myMock.h
#ifndef MYMOCK_H
#define MYMOCK_H
#include <gmock/gmock.h>
#include <QtCore/QObject>
#include "myInterfaceToMock.h"
class MyMock : public MyInterfaceToMock {
public:
// virtual bool myMethod(QVariant &firstArgument, const quint8 secondArgument)
// const = 0;
MOCK_METHOD(bool, myMethod, (QVariant &, const quint8), (const, override));
// virtual bool myMethod(QByteArray &firstArgument, const quint16
// secondArgument) const = 0;
MOCK_METHOD(bool, myMethod, (QByteArray &, const quint16), (const, override));
// virtual bool myOtherMethod(quint8 firstAndOnlyArgument) const = 0;
MOCK_METHOD(bool, myOtherMethod, (quint8), (const, override));
};
#endif // MYMOCK_H
main.cpp
#include <gmock/gmock-matchers.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <QCoreApplication>
#include <QTimer>
class Tester : public QObject {
Q_OBJECT
public:
Tester(QObject *parent = nullptr) : QObject(parent) {}
public slots:
void run() {
::testing::InitGoogleTest();
emit(result(RUN_ALL_TESTS()));
}
signals:
void result(int res);
};
#include "main.moc"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
::testing::InitGoogleMock(&argc, argv);
Tester *tester = new Tester(&app);
QObject::connect(tester, &Tester::result, &app, &QCoreApplication::exit);
QTimer::singleShot(0, tester, SLOT(run()));
return app.exec();
}
#include "myMock.h"
TEST(myTest, testMockOverload) {
using namespace testing;
MyMock mock;
// Reference method, which does work all the time
EXPECT_CALL(mock, myOtherMethod(_)).WillRepeatedly(Return(false));
// Using a defined value as argument
QVariant myVariant;
EXPECT_CALL(mock, myMethod(myVariant, 3)).WillOnce(Return(true));
bool result = mock.myMethod(myVariant, 3);
ASSERT_TRUE(result);
// Anything matcher for the unambiguous argument
EXPECT_CALL(mock, myMethod(myVariant, _)).WillOnce(Return(true));
result = mock.myMethod(myVariant, 3);
ASSERT_TRUE(result);
// Trying to match any passed qvariant
EXPECT_CALL(mock, myMethod(An<QVariant>(), _)).WillOnce(Return(true));
}
The compiler error is issued for the last line:
..\googlemock_disambiguate\main.cpp(55): error C2664: 'testing::internal::MockSpec<bool (QByteArray &,quint16)> MyMock::gmock_myMethod(const testing::internal::WithoutMatchers &,const testing::internal::Function<bool (QByteArray &,quint16)> *) const': cannot convert argument 1 from 'testing::Matcher<QVariant>' to 'const testing::Matcher<QVariant &> &'
..\googlemock_disambiguate\main.cpp(55): note: Reason: cannot convert from 'testing::Matcher<QVariant>' to 'const testing::Matcher<QVariant &>'
..\googlemock_disambiguate\main.cpp(55): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
I have a guess that it might have sth. to do with the constness of the method, but I still do not understand the meaning of that error...
Using An<type> is the correct solution.
EXPECT_CALL(mockedClass,mockedMethod(_, An<type>())).WillOnce(Return(true));
If it doesn't work for you, the problem lies elsewhere. Perhaps you can elaborate?
Answering the question myself:
I simply did not specify the type correctly, since I expect a reference to get passed. I always tried to use something like An<type>(), where I should have used An<type&>() instead.
So, based on my above example, the correct line simply is:
EXPECT_CALL(mock, myMethod(An<QVariant&>(), _)).WillOnce(Return(true));

Callbacks in C++ for an Arduino project

I am working on a Particle project and coming from JS so I'm challenged by callbacks in C++. I am trying to refactor my Firebase code into a reusable class and for this I need callbacks:
void setup() {
firebase = new Firebase;
Serial.begin(9600);
firebase->subscribe();
firebase->setCallback(readCallback);
}
void readCallback(JsonObject& root)
{
r = root["r"];
g = root["g"];
b = root["b"];
Serial.printlnf("Yes! r=%d g=%d b=%d d=%d", r, g, b);
}
Firebase.h:
#ifndef Firebase_h
#define Firebase_h
#include <SparkJson.h>
class Firebase {
public:
Firebase();
void
subscribe(),
setCallback(void (*readCallback)(JsonObject& root));
private:
static void getDataHandler(const char *topic, const char *data);
void (*_readCallback)(JsonObject& root);
};
#endif
Firebase.m:
#include "Particle.h"
// This #include statement was automatically added by the Particle IDE.
#include <SparkJson.h>
#include "ArduinoJson.h"
#include "Firebase.h"
Firebase::Firebase(void) {
Serial.printlnf("Firebase instance created");
}
void Firebase::getDataHandler(const char *topic, const char *data) {
Serial.printlnf("getDataHandler invoked");
StaticJsonBuffer<256> jsonBuffer;
char *mutableCopy = strdup(data);
JsonObject& root = jsonBuffer.parseObject(mutableCopy);
free(mutableCopy);
Serial.printlnf("data received: %s", data);
// _readCallback(root);
}
void Firebase::subscribe() {
Serial.printlnf("Firebase subscribe");
Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);
}
void Firebase::setCallback(void (*readCallback)(JsonObject& root))
{
Serial.printlnf("set callback");
_readCallback = readCallback;
}
When getDataHandler is static everything seems to work but naturally I am having trouble accessing the callback and I get:
invalid use of member 'Firebase::_readCallback' in static member
function
When it's not static I get for this line:
Particle.subscribe("hook-response/test3rdata", getDataHandler, MY_DEVICES);
the following error:
invalid use of non-static member function
When I try to bind it as advised here:
Particle.subscribe("hook-response/test3rdata", std::bind(&Firebase::getDataHandler,this), MY_DEVICES);
I get a mistype as Particle.subscribe does not expect a binded method:
no matching function for call to 'CloudClass::subscribe(const char
[25], std::_Bind_helper::type, Spark_Subscription_Scope_TypeDef)'
Is there a way around it?
You are getting this error because std::bind returns a function object that adheres to the signature void() and not void(char const*, char const*). The reason being, that you didn't specify any placeholders for those arguments. So a quick fix would be:
std::bind(&Firebase::getDataHandler, this, std::placeholders::_1, std::placeholders::_2)
Now the bind helper expects two parameters which it will forward to the bound member function.
Having said all that, there is no reason to use std::bind if a lambda will suffice. Lambdas are in fact superior in most regards. In C++14 there's virtually no reason to use std::bind at all. And even in C++11, your use case can be dealt with by a simple lambda:
Particle.subscribe("hook-response/test3rdata", [this](char const* a, char const* b) { getDataHandler(a, b); }, MY_DEVICES);

how to use object global after declaring its constructor in header file in c++?

I have two files :
// main.h
// some code ...
QSqlQuery getCardsQuery;
void readCardsFromDataBase();
void createCard();
//some code
// continue and end of main.h
//main.cpp
void MainWindow::readCardsFromDataBase()
{
myDataBase = QSqlDatabase::addDatabase("QMYSQL", "my_sql_db");
myDataBase.setHostName("localhost");
myDataBase.setDatabaseName("Learn");
myDataBase.setUserName("root");
myDataBase.setPassword("password");
bool ok = myDataBase.open();
qDebug()<< ok;
if (!ok)
QMessageBox::warning(this, "connection Error", "cannot connect to DataBase");
getCardsQuery("select Question, Answer, MainPosition, SecondPosition, IsMustReview\
from Cards", myDataBase); // I got error in here
///error: no match for call to '(QSqlQuery) (const char [106], QSqlDatabase&)'
}
void MainWindow::createCard()
{
getCardsQuery.next();
card = new Card(getCardsQuery.value(0).toString(), getCardsQuery.value(1).toString());
card->setPos(getCardsQuery.value(3).toInt(), getCardsQuery.value(4).toInt());
card->setReviewToday(getCardsQuery.value(4).toBool());
}
I got error when initialize getCardsQuery. I want to use getCardsQuery global.I want to initialze it like this :
getCardsQuery("select Question, Answer, MainPosition, SecondPosition, IsMustReview\
from Cards", myDataBase);
how can I declare it in header file and use globally in main.cpp file ?
Actually, you can declare getCardsQuery as your MainWindow class' member variable. The code below roughly demonstrates how to do that:
in main.h
class MainWindow : public QMainWindow
{
[..]
private:
QSqlQuery *getCardsQuery;
};
in main.cpp
MainWindow::MainWindow()
: getCardsQuery(0)
{}
void MainWindow::readCardsFromDataBase()
{
[..]
if (!getCardsQuery) {
getCardsQuery = new QSqlQuery("select Question, Answer," \
"MainPosition, SecondPosition," \
"IsMustReview from Cards", myDataBase);
}
[..]
}
void MainWindow::createCard()
{
if (!getCardsQuery) {
getCardsQuery->next();
[..]
}
}