PDA

View Full Version : Wrong C++ syntax



anneranch
6th December 2020, 17:19
This is very basic C++ stupid question.
Can somebody explain to me what I am doing wrong and / or correct my syntax so it will compile?







QObject::connect(ui->list, //object
&QListWidget::itemClicked(&item), //signal
ui->list_2, ///object
&QListWidget::addItem(&item)); //slot


// Edit
// After looking at some examples I have changed my code

// <pre lang="c++">
QObject ::connect(ui->list,
QListWidget.itemClicked(item),
ui->list_2,
QListWidget.addItem(item)
);





Fist "style " gives this error



/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:141: error: cannot call member function 'void QListWidget::itemClicked(QListWidgetItem*)' without object
&QListWidget::itemClicked(&item), //signal
^



Then I get this one



/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:153: error: expected primary-expression before '.' token
QListWidget.itemClicked(item),
^


Thanks

d_stranz
6th December 2020, 20:58
You are mixing up the two different styles of the connect() statement, the "old style", which used signal and slot names with arguments, and the "new style" which uses addresses of member functions. And in the old style, you do not use the names of variables as arguments, you use the type of the variable. So you can write either this:



// Old style

QObject::connect(ui->list, //object
SIGNAL( "itemClicked( QListWidgetItem * )" ), //signal
ui->list_2, ///object
SLOT( "addItem( QListWidgetItem * )" ) ); //slot


or this:



// New style

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
ui->list_2, //object
&QListWidget::addItem ); //slot


EXCEPT in this particular case, the "old style" will fail at run time because QListWidget::addItem() is not a slot so Qt's meta-object system will not be able to match up the "addItem()" method with anything declared as a slot in the QListWidget class.

The "new style" will work, because the matching of signal and slot is done at compile time, and a connect() statement in the new style can be between any two compatible methods, even an ordinary non-class method or a lambda.

anneranch
7th December 2020, 02:10
This is what I have been getting while using the "new style "

/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:140: error: no matching function for call to 'DeviceDiscoveryDialog::connect(QListWidget*&, void (QListWidget::*)(QListWidgetItem*), QListWidget*&, <unresolved overloaded function type>)'
&QListWidget::addItem ); //slot
^

d_stranz
7th December 2020, 16:32
This is because there are two QListWidget::addItem() methods, and the compiler doesn't know which one you want to use. So you have to be explicit in these cases, and there are two versions, one which works in C++11 or newer, then other requires C++14 or newer:



// New style, C++11 and up version

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
ui->list_2, //object
QOverload< QListWidgetItem * >::of( &QListWidget::addItem ) ); //slot


// New style, C++14 and up version

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
ui->list_2, //object
qOverload< QListWidgetItem * >( &QListWidget::addItem ) ); //slot

anneranch
8th December 2020, 17:28
I am sorry, but I have posted my question on so many forums I lost track where I stand.

So if this is a dupe, please forgive me.

I have C++11 (checked) and the compiler complains about this code :



// New style, C++11 and up version

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
ui->list_2, //object
QOverload< QListWidgetItem * >::of( &QListWidget::addItem ) ); //slot








/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:161: error: 'QOverload' was not declared in this scope
QOverload< QListWidgetItem * >::of( &QListWidget::addItem ) ); //slot
^


Adding QtGlobal did not resolve the issue.

After some research I found that "QOverload should be used directly in C++11 ".
Obviously I am having hard time undertaking "normal " "new syntax" of "connect" and have no clue how to apply QOverload directly.

More help would be greatly appreciated.

d_stranz
8th December 2020, 22:01
From the Qt docs:


This function was introduced in Qt 5.7.

Are you using Qt 5.7 or later? If not, then the only workarounds you have are 1) declare a slot in your class and connect that to itemClicked() and in that slot, call ui->list_2->addItem(). Or 2) use a lambda expression instead of a slot. Or, of course, 3) upgrade to Qt 5.7 or later.



// Case 1

// New style, C++11 and up version

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
this, //object
&MainWindow::doAddItem ) ); //slot

//...

void MainWindow::doAddItem( QListWidgetItem * pItem )
{
ui->list_2->addItem* pItem );
}


or



// Case 2

// New style, C++11 and up version

QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
this, //object
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ) } ); // lambda slot


However, you do realize what any of the methods you are trying will do, right? A QListWidgetItem can only belong to one QListWidget, so by calling addItem() on the second widget you are moving the QListWidgetItem from ui->list to ui->list_2. At the end of the slot, both list widgets will be updated and the item will disappear from ul->list and appear in ui->list_2.

anneranch
8th December 2020, 23:18
SOrry , cut and paste this:



QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
this, //object
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ) } );




trows this error




/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:180: error: expected ';' before '}' token
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ) } );
^



I have this :



Qt Creator 3.5.1
Based on Qt 5.5.1 (GCC 5.2.1 20151129, 64 bit)


Could that be part of my problem ??

d_stranz
9th December 2020, 00:43
No the problem is that you aren't thinking about the errors you see before you fire off another post. The compiler is telling you that I forgot to put a semicolon at the end of the addItem( pItem ) call. It's even pointing at the place where the error is. Put a semicolon between the ) and the } and it will compile. I do the best I can to post correct code, but sometimes typos creep in.



Qt Creator 3.5.1
Based on Qt 5.5.1 (GCC 5.2.1 20151129, 64 bit)


This is not telling you which version of Qt you have configured in your kit, it is telling you which version of Qt was used to build the Qt Creator software. The Qt versions used by the kit and by Qt Creator could be completely different. Look at the kit settings and that will tell you which Qt version you are compiling and linking against.

anneranch
9th December 2020, 01:52
I have briefly scanned this

https://en.cppreference.com/w/cpp/language/lambda
link
and managed to find the missing ";" .

Now I am getting this error



/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:181: error: no matching function for call to 'DeviceDiscoveryDialog::connect(QListWidget*&, void (QListWidget::*)(QListWidgetItem*), DeviceDiscoveryDialog*, DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidg et*)::<lambda(QListWidgetItem*)>)'
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); }) ;
^


I think I can fix that myself, (perhaps intelisense will help ) but I need to quit for today.
Thanks for your help.





QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
this, //object
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); }) ;

d_stranz
9th December 2020, 16:36
Sorry, I am typing faster than I am thinking. Try this:



QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
[this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); }) ; // lambda slot


There is no "receiver" pointer (the normal third argument to connect()) when using a connect() with the lambda syntax.

anneranch
9th December 2020, 20:43
Sorry, the original working XML code I am trying to test duplicate works between list and plain text .
However, even after modifying your lambda to plain text I get a same error - compiler does not like the "copy to" function.




QObject::connect(ui->list, //object
&QListWidget::itemClicked, //signal
[this]( QPlainTextEdit * pItem ) { this->ui->plainTextEdit->appendPlainText( pItem ); }) ; // lambda slot
// [this]( QListWidgetItem * pItem ) { this->ui->list_2->addItem( pItem ); }) ; // lambda slot







/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:154: error: no matching function for call to 'QPlainTextEdit::appendPlainText(QPlainTextEdit*&)'
[this]( QPlainTextEdit * pItem ) { this->ui->plainTextEdit->appendPlainText( pItem ); }) ; // lambda slot
^

Ginsengelf
10th December 2020, 07:15
Hi, your connect doesn't work because you use the itemClicked signal, which emits a pointer to a QListWidgetItem, as in d_stranz' code. But you try to connect it to a slot that takes a QPlaintextEdit*. The argument for your lambda slot needs to be the same type as the type that the signal emits.

Ginsengelf

d_stranz
10th December 2020, 17:23
However, even after modifying your lambda to plain text I get a same error - compiler does not like the "copy to" function.

Come on, quit screwing around here. Your original post asked how to connect a signal and slot between two QListWidget instances. The final code I posted would do that, using a lambda function instead of an actual slot. Now you say, I didn't want to connect to another list widget after all, I wanted to connect the list widget to a QPlainTextEdit.

You need to remember some basic C++. Signals and slots are no different from ordinary methods of C++ classes. They are labeled with "signals:" and "slots:" keywords in Qt so that the MOC compiler can recognize them and create the code in the moc_*.cpp file that implements them and makes the first style of connect() work at runtime. A lambda function is just a fancy way to write a nameless C++ function that gets compiled in place.

All the rules of C++ apply to signals, slots, and lambdas: If you want to call one of these functions, you have to supply the correct number and types of arguments to it. You can't call a function that expects one type of pointer using an argument that is a different type. It's basic C++, pure and simple.

anneranch
10th December 2020, 21:07
Come on, quit screwing around here. Your original post asked how to connect a signal and slot between two QListWidget instances. The final code I posted would do that, using a lambda function instead of an actual slot. Now you say, I didn't want to connect to another list widget after all, I wanted to connect the list widget to a QPlainTextEdit.

You need to remember some basic C++. Signals and slots are no different from ordinary methods of C++ classes. They are labeled with "signals:" and "slots:" keywords in Qt so that the MOC compiler can recognize them and create the code in the moc_*.cpp file that implements them and makes the first style of connect() work at runtime. A lambda function is just a fancy way to write a nameless C++ function that gets compiled in place.

All the rules of C++ apply to signals, slots, and lambdas: If you want to call one of these functions, you have to supply the correct number and types of arguments to it. You can't call a function that expects one type of pointer using an argument that is a different type. It's basic C++, pure and simple.

Sorry, but my objective, in case I did not say it - is to replace QtDesigner signal / slot in XML with C++ code.
The XML works by coping a string from list and appending it to plain text.

I initially started with list to list and have been getting "invalid function " when using "addItem", even when intelisense lets me use "addItem".
So I assumed I am using wrong syntax and still like to verify my mistake, irregardless if passing between item or plain text.
At this point I am not interested in bypassing my error using lambda - if XML works so should new or old style C++ "connect" work.

d_stranz
10th December 2020, 23:35
I am not interested in bypassing my error using lambda

Using a lambda expression does not bypass anything. It is simply an alternative to defining an actual slot or other method with the correct function signature. In your original post with two list widgets, you couldn't use the new style version of connect() that uses the QOverload<> syntax because your version of Qt is probably too old, and you couldn't use the old style version because it requires addItem() to be a slot and it isn't.

Now in your new code you are trying to connect a signal that sends an apple to a slot that wants an orange. Your error seems to be in thinking that somehow you can connect something to anything else and arguments will magically get converted. As I said already, signals and slots are just C++ functions, and you can't call a C++ function with the wrong number or types of arguments.


The XML works by coping a string from list and appending it to plain text.

How is that possible? There is no itemClicked() signal from QListWidget that sends a text string, so it is not possible in QtDesigner or anywhere else to connect a QListWidget itemClicked() signal to -any- slot that expects a text string as an argument. The ui XML code will compile, because the UIC and MOC compilers will create the old style connect() statement in its code, but it will not work at run time because the function signatures do not match.

The only QListWidget signal that returns a string is currentTextChanged(). So the only possible working signal / slot connection you could have made in QtDesigner would be to connect QListWidget::currentTextChanged() to QPlainTextEdit::appendPlainText(), and that will result in whatever text was clicked on in the list widget getting copied and appended to the text edit. Neither the signal nor the slot are overloaded methods, so you could use either the old or new style of connect() to make the connection.



connect( ui->list, SIGNAL( currentTextChanged( const QString & ) ), ui->plainTextEdit, SLOT( appendPlainText( const QString & ) ) );

// or

connect( ui->list, &QListWidget::currentTextChanged, ui->plainTextEdit, &QPlainTextEdit::appendPlainText );


In any case, there is no execution of XML code. The XML file edited by QtDesigner is simply instructions to the UIC and MOC compilers that tell them how to generate the C++ code that defines the user interfaces and instantiate it at run time, including making any signal and slot connections that have been defined in the ui file. That C++ code will always compile because connect() statements that get generated are the old style, which use method names as strings and not as addresses of member functions (as the new style does). New style connect() statements will fail to compile if the functions do not match. Old style connect() will compile, but at run time will fail because Qt's meta-object system will not be able to match up the function at that time.

anneranch
11th December 2020, 01:37
Partial success.
Using both old and new "connect" style throws "segmentation fault" at either one.

It is my understanding that "connect" code placement is not critical - however my crash occurs exactly on "connect" which I have placed in a secondary dialog constructor. My main window dialog is primary.

RTFM implies that passing null pointer may be the problem...

d_stranz
11th December 2020, 04:28
It is my understanding that "connect" code placement is not critical

No, not true. You must connect the signal and slot before any of the signals you want to process can be issued. The customary place to make the connection is in the constructor of the parent of the two widgets you want to connect. This ensures that the connection is made only once and before either of the connected widgets can do anything. There are other places, but this is the most common.


RTFM implies that passing null pointer may be the problem...

Almost always either a null pointer or a pointer that has not been initialized. If you are passing a pointer in to your secondary dialog via a function call, then calling connect() using the variable that holds that pointer before you have made that call (i.e. in the dialog constructor) means you are using an uninitialized pointer.