QT CPP How to solve ambiguous error when calling function? - c++

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

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)
{
}

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));

Arduino: pass function to class, returning String

I'm trying to get my Arduino class to return String messages with all kind of information for logging. With lots of trial and error I manage to pass a reference to the logging function to the class, but can only get a char* but not a String, and I want to be able to send Strings making it so much easier to send back all kinds of data.
I have the first part working already.
The sketch:
#include <Test.h>
#include <string.h>
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
The header file:
#ifndef TEST_h
#define TEST_h
class Test
{
public:
Test(); // The constructor.
void setLogging(void (*)(char*)); // Takes function setting where to log.
void doSomething(char*);
};
#endif
The class:
#include <Test.h>
typedef void (*LogFunction)(char*);
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
void Test::setLogging (void (*f)(char*) ) {
writeLog = f;
return;
}
Now what I want my class to be able to do is send information like this, as String, rather than char* (I also haven't found an easy way of converting "anything" to char* and then concatenating the two or more strings):
writeLog ("HydroMonitorECSensor::setCalibration Receiving calibration - haveCalibration = " + String(haveCalibration));
writeLog ("HydroMonitorECSensor::setCalibration calibratedSlope = " + String(calibratedSlope));
writeLog ("HydroMonitorECSensor::setPins capPos set to " + String(capPos));
Where haveCalibration is a bool (which as String becomes either "true" or "false"), calibratedSlope is a double and capPos is an int. This way I can easily and cleanly send complete lines to the logger. Works great within the main script - not from the class.
I tried simply changing the char* to String and adding #include <string.h> to the library files but it doesn't work.
In Test.cpp I then get void Test::setLogging (void (*f)(String) ) { and in Test.h void setLogging(void (*)(String)); and now I get error messages:
In file included from /home/wouter/Arduino/libraries/Test/Test.cpp:1:0:
/home/wouter/Arduino/libraries/Test/Test.h:10:29: error: expected ',' or '...' before '(' token
void setLogging(void (*)(String)); // Takes function setting where to log.
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:40: error: variable or field 'setLogging' declared void
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:31: error: 'f' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:34: error: 'String' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).
Suggestions?
Additional info, maybe important: I'm using the Arduino IDE and compile for ESP8266.
You are using the Arduino-provided String class, but didn't include the Arduino.h header in your test.h header file. That causes it to not find the String class and compilation fails.
The following works:
main.cpp:
#include <Arduino.h>
#include <test.hpp>
void writeLog (char* message);
void writeLog (String message);
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
test.hpp:
#ifndef TEST_h
#define TEST_h
#include <Arduino.h> //for "String" class
//Typdef for the log function. Takes a String, returns nothing
typedef void (*LogFunction)(String);
class Test
{
public:
Test(); // The constructor.
// void setLogging(void (*)(char*)); // Takes function setting where to log.
void setLogging(LogFunction); //use the typedef here
void doSomething(char*);
};
#endif
test.cpp:
#include <test.hpp>
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
//void Test::setLogging (void (*f)(char*) ) {
void Test::setLogging (LogFunction f) { //also use typedef here
writeLog = f;
return;
}
Among other things that may arise, the compiler tells you that it cannot resolve identifier String.
This can have several reasons: First, you write String, and not string (note the capital letter in your writing). Second, if you write string and not std::string, it cannot be resolved unless you have either declared using namespace std (which is not the preferred variant for several reasons) or using std::string. Third, class std::string is declared in header <string>, which is something different than <string.h>.
So I'd write #include <string> and use then std::string.

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();
[..]
}
}

QJsonValue is private?

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.