Help interpreting an error

I have some code that compiled fine with QNX4 and generates an error
when compiled with QNX6. I don’t understand what the error is telling
me. The error is:

xyz.cc:15: Request for member ‘Put’ in ‘log’, which is of non-aggrate type ‘LGadmin()()’
cc: /usr/lib/gcc-lib/ntox86/2.95.3/cc1plus error 33

Essentially, in a header file I have:

class LGadmin
{
// stuff
public:
int Put( int x, char * cp1, char * cp2 );
};

And in the main file I have:

LGadmin log;
int main ( )
{
log.Put( 1, “string1”, “string2” );
}

There are many Put() methods, each with a different argument list.

What am I doing wrong?

Bill Caroselli wrote:

I have some code that compiled fine with QNX4 and generates an error
when compiled with QNX6. I don’t understand what the error is telling
me. The error is:

xyz.cc:15: Request for member ‘Put’ in ‘log’, which is of non-aggrate type ‘LGadmin()()’
cc: /usr/lib/gcc-lib/ntox86/2.95.3/cc1plus error 33

I’d need an example that shows the error, but generally it means ‘log’
is not what you think it is :slight_smile: Most likely, it’s a pointer to an LGadmin
or you’ve declared ‘LGadmin log()’ ie ‘log’ is a function that returns
an LGadmin. In either case you can’t use the ‘.’ operator…

Essentially, in a header file I have:

class LGadmin
{
// stuff
public:
int Put( int x, char * cp1, char * cp2 );
};

And in the main file I have:

LGadmin log;
int main ( )
{
log.Put( 1, “string1”, “string2” );
}

There are many Put() methods, each with a different argument list.

What am I doing wrong?

I’m angry!

It turns out that I hadn’t posted the necessary thing that explains
this error.

The LGadmin class has a sole constructor that looks like this:
LGadmin ( int x = 0 );

I was instanciating this in global scope with:
LGadmin log();

As soon as I changed my instanciation to:
LGadmin log( 0 );
the error went away.

I have tens of thousands of lines of code that won’t port if I can’t
use default parameters on a conctrustor.

Why won’t this work?

Yes, I do realize thaht I can just write another constructor that
doesn’t have any arguments and pass the default value to the first
constructor. But I don’t want to. It looks sloppy.


Garry Turcotte <garry@qnx.com> wrote:
GT > Bill Caroselli wrote:

I have some code that compiled fine with QNX4 and generates an error
when compiled with QNX6. I don’t understand what the error is telling
me. The error is:

xyz.cc:15: Request for member ‘Put’ in ‘log’, which is of non-aggrate type ‘LGadmin()()’
cc: /usr/lib/gcc-lib/ntox86/2.95.3/cc1plus error 33

GT > I’d need an example that shows the error, but generally it means ‘log’
GT > is not what you think it is :slight_smile: Most likely, it’s a pointer to an LGadmin
GT > or you’ve declared ‘LGadmin log()’ ie ‘log’ is a function that returns
GT > an LGadmin. In either case you can’t use the ‘.’ operator…

Essentially, in a header file I have:

class LGadmin
{
// stuff
public:
int Put( int x, char * cp1, char * cp2 );
};

And in the main file I have:

LGadmin log;
int main ( )
{
log.Put( 1, “string1”, “string2” );
}

There are many Put() methods, each with a different argument list.

What am I doing wrong?


Bill Caroselli – Q-TPS Consulting
1-(708) 308-4956 <== Note: New Number
qtps@earthlink.net

Bill Caroselli <qtps@earthlink.net> wrote:

BC > Yes, I do realize thaht I can just write another constructor that
BC > doesn’t have any arguments and pass the default value to the first
BC > constructor. But I don’t want to. It looks sloppy.


And actually I can’t do this anyway.

I found out further that with the single constructor:
LGadmin ( int x = 0 );

I can instanciate it with:
LGadmin log;
But not with:
LGadmin log();

Watcom/QNX4 accepted both.

I can live with that, but I’m still not happy.

Bill Caroselli <qtps@earthlink.net> wrote:

I found out further that with the single constructor:
LGadmin ( int x = 0 );

I can instanciate it with:
LGadmin log;
But not with:
LGadmin log();

Of course not – the above is a function declaration, equivalent to

LGadmin log( void );

Watcom/QNX4 accepted both.

Not the version I have here:

$ cc foo.cc || cat foo.cc
/usr/watcom/10.7/bin/wpp386 -zq -ms -3r -i=/usr/include -i=/usr/watcom/10.7/usr/include foo.cc
foo.cc(13): Error! E040: (col 10) expression for ‘.’ must be a class, struct or union
cc: /usr/watcom/10.7/bin/wpp386 exited 2
#include <stdio.h>

class X {
int val;
public:
X( int v = 0 ) : val(v) {}
foo( void ) { printf( “%d\n”, val ); }
};

X x();

int main( void ) {
x.foo();
return 0;
}

“Wojtek Lerch” <wojtek_l@yahoo.ca> wrote in message
news:boe1qp$81j$1@inn.qnx.com

Bill Caroselli <> qtps@earthlink.net> > wrote:

I found out further that with the single constructor:
LGadmin ( int x = 0 );

I can instanciate it with:
LGadmin log;
But not with:
LGadmin log();

Of course not – the above is a function declaration, equivalent to

LGadmin log( void );

In other words, what you are running into is a result of the tension between
retention of backwards compatibility with C, and the formal semantics of
C++.

The application doesn’t conform to the specifications, and the version of
Watcom –
is it 10.6? – fails to catch the error.

Specifically, C compatibility in C++ from its non-standard origins, through
the
ARM/ANSI base document and eventually to ISO C++, specifies that a
declaration of the form:

();

is equivalent to the following declaration:

(void);

Note: it specifically disallows “()” as meaning an uncertain argument list,
but retains
it as a no-argument list.

However, the ambiguity resolution rules state that any statement that may be
interpreted
as either a declaration or an expression, shall be considered to be a
declaration (ARM
section 6.8, ISO C++ section 8.2).

This means that, while what you expect is an initializer, and therefore an
expression, it is
interpreting as a declaration of a function, so the log.Put is not
syntactically correct, since
the “.” member accessor is only valid for an aggregate type, but the type of
log is a function
declaration, so the resulting expression may only be a function reference.

Note that even if it interpreted:
LGAdmin log();

as an initializer, you’d still be in trouble, because the
LGAdmin::LGAdmin(int x = 0)
and LGAdmin::LGAdmin(void) could not be disambiguated. Although, you may
not believe there is an LGAdmin::LGAdmin(void), don’t forget that the
compiler
will always generate one if it doesn’t exist as with copy constructors, to
provide
proper initializer behavior.

So, while you view:

LGAdmin::LGAdmin(void) : LGAdmin(0) { }

LGAdmin log;

as ugly, it is correct from two perspectives: avoiding ambiguity, as well as
avoiding implicit dependencies on compiler-generated constructors.



Watcom/QNX4 accepted both.

Not the version I have here:

$ cc foo.cc || cat foo.cc

/usr/watcom/10.7/bin/wpp386 -zq -ms -3r -i=/usr/include -i=/usr/watcom/10.7/

usr/include foo.cc

foo.cc(13): Error! E040: (col 10) expression for ‘.’ must be a class,
struct or union
cc: /usr/watcom/10.7/bin/wpp386 exited 2
#include <stdio.h

class X {
int val;
public:
X( int v = 0 ) : val(v) {}
foo( void ) { printf( “%d\n”, val ); }
};

X x();

int main( void ) {
x.foo();
return 0;
}

OK. Gee, I learned something today.

Steve Furr <furr@qnx.com> wrote:

[Lots-O-Good-Stuff Deleted]

SF > So, while you view:

SF > LGAdmin::LGAdmin(void) : LGAdmin(0) { }
SF > …
SF > LGAdmin log;

SF > as ugly, it is correct from two perspectives: avoiding ambiguity, as well as
SF > avoiding implicit dependencies on compiler-generated constructors.


OK. Two last questions.

I understand the necessity of ‘LGadmin log;’ instead of ‘LGadmin log();’

Are you suggesting that the declairation ‘LGadmin ( int x = 0 )’
[I.E. using a default parameter] should not be used? That part does
seem to work.

I don’t understand the syntacticle justification for
LGAdmin::LGAdmin(void) : LGAdmin(0) { }

I understood that a constructor may have an initializer list (the
‘LGAdmin(0)’ part above) that either initialized it’s base classes or
it’s own members.

The way you’ve coded this implies that a class is a base class of
itself. Which I guess might be philosophicly true (kind of like a set
is a subset of itself). But if we assume that it is true that a class
is a base class of itself, then it would also be infintly recursivly
true. And a class constructor must construct it’s base classes before
it can construct itself.

“Let’s do the time warp again!”

Anyway, I’ve solved my problem and I am grateful to all who replied.
You needn’t reply unless it’s just for the fun of kicking around the
idea for a little more.

Thanks.

Sorry, I was glossing, and really shouldn’t have implied an initializer list
(you might
be doing member initializations directly OR chaining a constructor, but
inside the
body – see below for why that’s not great).

The trivialized approach is to use LGAdmin::LGAdmin(void) { LGAdmin(0); }

What you actually want to do is more complicated, since the above constructs
a temporary LGAdmin and invokes a copy constructor. So, what you want
is an init function with default parameters, that you invoke from various
constructors.

For various reasons, a canonical class form is advisable:

class Canonical {
public:
Canonical(); /* Other constructors as well /
void init(/
full parameter list, with some potentially optional /);
/
Common initialization */
virtual ~Canonical();
private:
Canonical(Canonical &c) {};
Canonical(const Canonical &c) {};
Canonical & operator = (Canonical &c) {};
Canonical & operator = (const Canonical &c) {};
};

Deviation is the exception rather than the norm, for safety reasons:

  • to prevent arbitrary bit-wise copying and assignment. i.e. only
    provide public forms when it is guaranteed bitwise copying is safe, or
    if a safe implementation is provided
  • for predictability – prevent inadvertant chaining of invocations
  • only provide a non-virtual destructor if derived classes aren’t allowed
    or under similar controlled conditions (leaks, etc.)

“Bill Caroselli” <qtps@earthlink.net> wrote in message
news:boh46c$dk8$1@inn.qnx.com

OK. Gee, I learned something today.

Steve Furr <> furr@qnx.com> > wrote:

[Lots-O-Good-Stuff Deleted]

SF > So, while you view:

SF > LGAdmin::LGAdmin(void) : LGAdmin(0) { }
SF > …
SF > LGAdmin log;

SF > as ugly, it is correct from two perspectives: avoiding ambiguity, as
well as
SF > avoiding implicit dependencies on compiler-generated constructors.


OK. Two last questions.

I understand the necessity of ‘LGadmin log;’ instead of ‘LGadmin log();’

Are you suggesting that the declairation ‘LGadmin ( int x = 0 )’
[I.E. using a default parameter] should not be used? That part does
seem to work.

I don’t understand the syntacticle justification for
LGAdmin::LGAdmin(void) : LGAdmin(0) { }

I understood that a constructor may have an initializer list (the
‘LGAdmin(0)’ part above) that either initialized it’s base classes or
it’s own members.

The way you’ve coded this implies that a class is a base class of
itself. Which I guess might be philosophicly true (kind of like a set
is a subset of itself). But if we assume that it is true that a class
is a base class of itself, then it would also be infintly recursivly
true. And a class constructor must construct it’s base classes before
it can construct itself.

“Let’s do the time warp again!”

Anyway, I’ve solved my problem and I am grateful to all who replied.
You needn’t reply unless it’s just for the fun of kicking around the
idea for a little more.

Thanks.