Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 8

Qt-interest Archive, March 2002
Possible slot/signal connection bug, 'const' ignored


Message 1 in thread

I have two slots both called 'invoke()', one takes a 'QByteArray&' and the 
other takes a 'const QByteArray&' argument. If I connect a signal of type 
'const QByteArray&' to the slot of type 'const QByteArray&', the wrong slot 
is called - the non-const slot of type 'QByteArray&'.

signals:
	void testSignal1(QByteArray&);
	void testSignal2(const QByteArray&);
public slots:
	void invoke(QByteArray&);
	void invoke(const QByteArray&);
...

    connect(this,SIGNAL(testSignal1(QByteArray&)),
               this, SLOT(invoke(QByteArray&)));

    connect(this,SIGNAL(testSignal2(const QByteArray&)), 
              this, SLOT(invoke(const QByteArray&)));
...

void TestMOC::invoke(QByteArray& arg)
{
	printf("In slotTest1()\n");
}

void TestMOC::invoke(const QByteArray& arg)
{
	printf("In slotTest2()\n");
}

	QByteArray test;
	emit(testSignal1(test));
	emit(testSignal2(test));

Produces the following output:

In slotTest1()
In slotTest1()

I am using the current version of qt-copy from the KDE cvs.

-- Richard


Message 2 in thread

I made just a same example you wrote and executed with g++ 
(gcc version 2.95.4) and qt-x11-2.3.1 on GNU/Linux.

To my surprise the output was:

  In slotTest1()
  In slotTest2()

Please check QMetaObject* TestMOC::staticMetaObject() in 
TestMOC.moc.cpp.
If my case the slot_tbl was initialized like:

  slot_tbl[0].name = "invoke(QByteArray&)";
  slot_tbl[0].ptr = (QMember)ov1_0;
  slot_tbl_access[0] = QMetaData::Public;
  slot_tbl[1].name = "invoke(const QByteArray&)";
  slot_tbl[1].ptr = (QMember)ov1_1;
  slot_tbl_access[1] = QMetaData::Public;


On 2002 March 23 Saturday 00:32, Richard Dale wrote:
> I have two slots both called 'invoke()', one takes a
> 'QByteArray&' and the other takes a 'const QByteArray&'
> argument. If I connect a signal of type 'const
> QByteArray&' to the slot of type 'const QByteArray&', the
> wrong slot is called - the non-const slot of type
> 'QByteArray&'.
>
> signals:
> 	void testSignal1(QByteArray&);
> 	void testSignal2(const QByteArray&);
> public slots:
> 	void invoke(QByteArray&);
> 	void invoke(const QByteArray&);
> ...
>
>     connect(this,SIGNAL(testSignal1(QByteArray&)),
>                this, SLOT(invoke(QByteArray&)));
>
>     connect(this,SIGNAL(testSignal2(const QByteArray&)),
>               this, SLOT(invoke(const QByteArray&)));
> ...
>
> void TestMOC::invoke(QByteArray& arg)
> {
> 	printf("In slotTest1()\n");
> }
>
> void TestMOC::invoke(const QByteArray& arg)
> {
> 	printf("In slotTest2()\n");
> }
>
> 	QByteArray test;
> 	emit(testSignal1(test));
> 	emit(testSignal2(test));
>
> Produces the following output:
>
> In slotTest1()
> In slotTest1()
>
> I am using the current version of qt-copy from the KDE
> cvs.
>
> -- Richard

Message 3 in thread

Hi Richard

I am really wondering why this code is compiling. According to the
Stroustrup bible (The C++ Programming Language, chapter 7.4 (Overloaded
Function Names)), the type for the overloaded function should differ by more
than just by constness.

But now I made a small example and the compiler can really handle that! I
checked it with g++ on Linux and with the MIPSpro compiler on Irix.

What I believe is that in the signal/slot case the arguments must differ
more than just by constness.

Hope that helped.

With kind regards
Beat Schaer


> -----Original Message-----
> From: Richard Dale [mailto:Richard_Dale@tipitina.demon.co.uk]
> Sent: Friday, March 22, 2002 4:32 PM
> To: QT-Interest
> Subject: Possible slot/signal connection bug, 'const' ignored
> 
> 
> I have two slots both called 'invoke()', one takes a 
> 'QByteArray&' and the 
> other takes a 'const QByteArray&' argument. If I connect a 
> signal of type 
> 'const QByteArray&' to the slot of type 'const QByteArray&', 
> the wrong slot 
> is called - the non-const slot of type 'QByteArray&'.
> 
> signals:
> 	void testSignal1(QByteArray&);
> 	void testSignal2(const QByteArray&);
> public slots:
> 	void invoke(QByteArray&);
> 	void invoke(const QByteArray&);
> ...
> 
>     connect(this,SIGNAL(testSignal1(QByteArray&)),
>                this, SLOT(invoke(QByteArray&)));
> 
>     connect(this,SIGNAL(testSignal2(const QByteArray&)), 
>               this, SLOT(invoke(const QByteArray&)));
> ...
> 
> void TestMOC::invoke(QByteArray& arg)
> {
> 	printf("In slotTest1()\n");
> }
> 
> void TestMOC::invoke(const QByteArray& arg)
> {
> 	printf("In slotTest2()\n");
> }
> 
> 	QByteArray test;
> 	emit(testSignal1(test));
> 	emit(testSignal2(test));
> 
> Produces the following output:
> 
> In slotTest1()
> In slotTest1()
> 
> I am using the current version of qt-copy from the KDE cvs.
> 
> -- Richard
> 
> --
> List archive and information: http://qt-interest.trolltech.com
> 


Message 4 in thread

> Hi Richard
>
> I am really wondering why this code is compiling. According to the
> Stroustrup bible (The C++ Programming Language, chapter 7.4 (Overloaded
> Function Names)), the type for the overloaded function should differ by
more
> than just by constness.
>
Thats strange, since Stroustrup takes the trouble to explain it very clearly
in the ARM.

This is illegal:

int f(int i)
{
...
}
int f(const int i)
{
...
}

But this is OK:

int f(int& i)
{
...
}
int f(const int& i)
{
...
}


> But now I made a small example and the compiler can really handle that! I
> checked it with g++ on Linux and with the MIPSpro compiler on Irix.
>
> What I believe is that in the signal/slot case the arguments must differ
> more than just by constness.
>
> Hope that helped.
>
> With kind regards
> Beat Schaer
>
>
> > -----Original Message-----
> > From: Richard Dale [mailto:Richard_Dale@tipitina.demon.co.uk]
> > Sent: Friday, March 22, 2002 4:32 PM
> > To: QT-Interest
> > Subject: Possible slot/signal connection bug, 'const' ignored
> >
> >
> > I have two slots both called 'invoke()', one takes a
> > 'QByteArray&' and the
> > other takes a 'const QByteArray&' argument. If I connect a
> > signal of type
> > 'const QByteArray&' to the slot of type 'const QByteArray&',
> > the wrong slot
> > is called - the non-const slot of type 'QByteArray&'.
> >
> > signals:
> > void testSignal1(QByteArray&);
> > void testSignal2(const QByteArray&);
> > public slots:
> > void invoke(QByteArray&);
> > void invoke(const QByteArray&);
> > ...
> >
> >     connect(this,SIGNAL(testSignal1(QByteArray&)),
> >                this, SLOT(invoke(QByteArray&)));
> >
> >     connect(this,SIGNAL(testSignal2(const QByteArray&)),
> >               this, SLOT(invoke(const QByteArray&)));
> > ...
> >
> > void TestMOC::invoke(QByteArray& arg)
> > {
> > printf("In slotTest1()\n");
> > }
> >
> > void TestMOC::invoke(const QByteArray& arg)
> > {
> > printf("In slotTest2()\n");
> > }
> >
> > QByteArray test;
> > emit(testSignal1(test));
> > emit(testSignal2(test));
> >
> > Produces the following output:
> >
> > In slotTest1()
> > In slotTest1()
> >
> > I am using the current version of qt-copy from the KDE cvs.
> >
> > -- Richard
> >
> > --
> > List archive and information: http://qt-interest.trolltech.com
> >
>
> --
> List archive and information: http://qt-interest.trolltech.com


Message 5 in thread

On Friday 22 March 2002 4:56 pm, Paul Robertson wrote:
> > On Friday 22 March 2002 4:26 pm, beat.schaer@ruag.com wrote:
> > I am really wondering why this code is compiling. According to the
> > Stroustrup bible (The C++ Programming Language, chapter 7.4 (Overloaded
> > Function Names)), the type for the overloaded function should differ by
> > more
> > than just by constness.
>
> Thats strange, since Stroustrup takes the trouble to explain it very
> clearly in the ARM.
>
> This is illegal:
>
> int f(int i)
> {
> ...
> }
> int f(const int i)
> {
> ...
> }
>
> But this is OK:
>
> int f(int& i)
> {
> ...
> }
> int f(const int& i)
> {
> ...
> }
>
> > But now I made a small example and the compiler can really handle that! I
> > checked it with g++ on Linux and with the MIPSpro compiler on Irix.
> >
> > What I believe is that in the signal/slot case the arguments must differ
> > more than just by constness.
The problem is a bug in the Qt 3.x moc. It generates two function calls 
'qt_invoke()' and 'qt_emit()'.

bool TestMOC::qt_invoke( int _id, QUObject* _o )
{
    switch ( _id - staticMetaObject()->slotOffset() ) {
    case 0: invoke(*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
    case 1: invoke(*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
...

bool TestMOC::qt_emit( int _id, QUObject* _o )
{
    switch ( _id - staticMetaObject()->signalOffset() ) {
    case 0: testSignal1(*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
    case 1: testSignal2(*((QByteArray*)static_QUType_ptr.get(_o+1))); break;

The same invoke() slot is called for both 'QByteArray&' and 'const 
QByteArray&', and similarly the signals 'testSignal1' and 'testSignal2' have 
the same type. The generated code needs to be changed to add an appropriate 
cast for const/non-const reference types to ensure that overloading works 
correctly:

bool TestMOC::qt_invoke( int _id, QUObject* _o )
{
    switch ( _id - staticMetaObject()->slotOffset() ) {
    case 0: invoke((QByteArray&)*((QByteArray*)static_QUType_ptr.get(_o+1))); 
break;
    case 1: invoke((const 
QByteArray&)*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
...

bool TestMOC::qt_emit( int _id, QUObject* _o )
{
    switch ( _id - staticMetaObject()->signalOffset() ) {
    case 0: 
testSignal1((QByteArray&)*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
    case 1: testSignal2((const 
QByteArray&)*((QByteArray*)static_QUType_ptr.get(_o+1))); break;
...

I've attached a small patch for the moc which fixes the problem. Copy 
'moc_constref.patch' to $QTDIR/src

$ cd $QTDIR/src/moc
$ patch -p1 < ../moc_constref.patch

Then build Qt as normal.

-- Richard

> > > -----Original Message-----
> > > From: Richard Dale [mailto:Richard_Dale@tipitina.demon.co.uk]
> > > Sent: Friday, March 22, 2002 4:32 PM
> > > To: QT-Interest
> > > Subject: Possible slot/signal connection bug, 'const' ignored
> > >
> > >
> > > I have two slots both called 'invoke()', one takes a
> > > 'QByteArray&' and the
> > > other takes a 'const QByteArray&' argument. If I connect a
> > > signal of type
> > > 'const QByteArray&' to the slot of type 'const QByteArray&',
> > > the wrong slot
> > > is called - the non-const slot of type 'QByteArray&'.
> > >
> > > signals:
> > > void testSignal1(QByteArray&);
> > > void testSignal2(const QByteArray&);
> > > public slots:
> > > void invoke(QByteArray&);
> > > void invoke(const QByteArray&);
> > > ...
> > >
> > >     connect(this,SIGNAL(testSignal1(QByteArray&)),
> > >                this, SLOT(invoke(QByteArray&)));
> > >
> > >     connect(this,SIGNAL(testSignal2(const QByteArray&)),
> > >               this, SLOT(invoke(const QByteArray&)));
> > > ...
> > >
> > > void TestMOC::invoke(QByteArray& arg)
> > > {
> > > printf("In slotTest1()\n");
> > > }
> > >
> > > void TestMOC::invoke(const QByteArray& arg)
> > > {
> > > printf("In slotTest2()\n");
> > > }
> > >
> > > QByteArray test;
> > > emit(testSignal1(test));
> > > emit(testSignal2(test));
> > >
> > > Produces the following output:
> > >
> > > In slotTest1()
> > > In slotTest1()
> > >
> > > I am using the current version of qt-copy from the KDE cvs.
> > >
> > > -- Richard
> > >
> > > --
> > > List archive and information: http://qt-interest.trolltech.com
> >
> > --
> > List archive and information: http://qt-interest.trolltech.com


diff -Naur -X /home/duke/bin/patcher.exclude temp/moc.y moc/moc.y
--- temp/moc.y	Sun Mar 24 04:02:21 2002
+++ moc/moc.y	Sun Mar 24 04:12:34 2002
@@ -3253,7 +3253,7 @@
 		    else
 			fprintf( out, "static_QUType_%s.get(_o+%d)", utype.data(), offset+1 );
 		} else {
-		    fprintf( out, "*((%s*)static_QUType_ptr.get(_o+%d))", referencePlainUType( type) .data(), offset+1 );
+		    fprintf( out, "(%s)*((%s*)static_QUType_ptr.get(_o+%d))", type.data(), referencePlainUType( type) .data(), offset+1 );
 		}
 		a = f->args->next();
 		if ( a )
@@ -3321,7 +3321,7 @@
 		    else
 			fprintf( out, "static_QUType_%s.get(_o+%d)", utype.data(), offset+1 );
 		} else {
-		    fprintf( out, "*((%s*)static_QUType_ptr.get(_o+%d))", referencePlainUType(type).data(), offset+1 );
+		    fprintf( out, "(%s)*((%s*)static_QUType_ptr.get(_o+%d))", type.data(), referencePlainUType(type).data(), offset+1 );
 		}
 		a = f->args->next();
 		if ( a )

Message 6 in thread

On Friday 22 March 2002 4:26 pm, beat.schaer@ruag.com wrote:
> I am really wondering why this code is compiling. According to the
> Stroustrup bible (The C++ Programming Language, chapter 7.4 (Overloaded
> Function Names)), the type for the overloaded function should differ by
> more than just by constness.
>
> But now I made a small example and the compiler can really handle that! I
> checked it with g++ on Linux and with the MIPSpro compiler on Irix.
>
> What I believe is that in the signal/slot case the arguments must differ
> more than just by constness.
>
> Hope that helped.
Well yes, but I've still got a problem which I'll need to work round in one of 
two ways. Either rename the slots 'invokeconst' if they contain a const 
string, or make do with just the non-const slot types. I've just tried the 
code with Qt-2.3.2 (as opposed to Qt 3.0.3) and my example used to work.

Here is a comment from qobject.cpp about the behaviour of Qt when matching 
slot/signal type signatures with const modifiers in them:

/*!
  \fn bool QObject::checkConnectArgs( const char *signal, const QObject 
*receiver, const char *member )

  Returns TRUE if the \a signal and the \a member arguments are compatible;
  otherwise returns FALSE. (The \a receiver argument is currently ignored.)

  \warning
  We recommend that you use the default implementation and do not
  reimplement this function.

  \omit
  TRUE:  "signal(<anything>)",  "member()"
  TRUE:  "signal(a,b,c)",       "member(a,b,c)"
  TRUE:  "signal(a,b,c)",       "member(a,b)", "member(a)" etc.
  FALSE: "signal(const a)",     "member(a)"
  FALSE: "signal(a)",           "member(const a)"
  FALSE: "signal(a)",           "member(b)"
  FALSE: "signal(a)",           "member(a,b)"
*/

bool QObject::checkConnectArgs( const char    *signal,
...

If Qt didn't want to distiguish between them, wouldn't it just strip them out? 
Then there would be no need for a comment like the one above.

-- Richard

> > -----Original Message-----
> > From: Richard Dale [mailto:Richard_Dale@tipitina.demon.co.uk]
> > Sent: Friday, March 22, 2002 4:32 PM
> > To: QT-Interest
> > Subject: Possible slot/signal connection bug, 'const' ignored
> >
> >
> > I have two slots both called 'invoke()', one takes a
> > 'QByteArray&' and the
> > other takes a 'const QByteArray&' argument. If I connect a
> > signal of type
> > 'const QByteArray&' to the slot of type 'const QByteArray&',
> > the wrong slot
> > is called - the non-const slot of type 'QByteArray&'.
> >
> > signals:
> > 	void testSignal1(QByteArray&);
> > 	void testSignal2(const QByteArray&);
> > public slots:
> > 	void invoke(QByteArray&);
> > 	void invoke(const QByteArray&);
> > ...
> >
> >     connect(this,SIGNAL(testSignal1(QByteArray&)),
> >                this, SLOT(invoke(QByteArray&)));
> >
> >     connect(this,SIGNAL(testSignal2(const QByteArray&)),
> >               this, SLOT(invoke(const QByteArray&)));
> > ...
> >
> > void TestMOC::invoke(QByteArray& arg)
> > {
> > 	printf("In slotTest1()\n");
> > }
> >
> > void TestMOC::invoke(const QByteArray& arg)
> > {
> > 	printf("In slotTest2()\n");
> > }
> >
> > 	QByteArray test;
> > 	emit(testSignal1(test));
> > 	emit(testSignal2(test));
> >
> > Produces the following output:
> >
> > In slotTest1()
> > In slotTest1()
> >
> > I am using the current version of qt-copy from the KDE cvs.
> >
> > -- Richard
> >
> > --
> > List archive and information: http://qt-interest.trolltech.com