Different results from different gcc versions

K

ks

Hi,

I have a problem with a piece of code. I'm in a situation where I have
to compile code using 2 different g++ compilers (2.95 and 4.12). I've
reduced the issue to a small, self contained program (given below)

//-------------------------------------
START----------------------------
#include <stdio.h>

struct A {
int a;
int b;
} ;

namespace NS {
void func(struct A *, int);
}

void NS::func(struct A * a_ptr, int i)
{
printf("%ld %d\n", a_ptr, i);
return;
}

namespace NS {
struct A : public ::A {} ;
}

struct NS::A* get_A(void)
{
return (struct NS::A *) 0;
}

int main()
{

func(get_A(), 1);
}
//--------------------------------
END----------------------------------
This program compiles on g++ 4.12 but fails on g++ 2.95 with the
following error:

test.cpp: In function `int main()':
test.cpp:30: implicit declaration of function `int func(...)'

If I change the call from func(...) to NS::func(...), both the
compilers are happy. I can understand the reason for that. However,
how does the g++ 4.12 compiler build without explicitly specifying the
namespace?

Which is the correct behavior?

Thanks
SK
 
A

Alf P. Steinbach

* ks:
Hi,

I have a problem with a piece of code. I'm in a situation where I have
to compile code using 2 different g++ compilers (2.95 and 4.12). I've
reduced the issue to a small, self contained program (given below)

//-------------------------------------
START----------------------------
#include <stdio.h>

struct A {
int a;
int b;
} ;

namespace NS {
void func(struct A *, int);
}

void NS::func(struct A * a_ptr, int i)
{
printf("%ld %d\n", a_ptr, i);

This should probably be a p-format.

return;
}

namespace NS {
struct A : public ::A {} ;
}

struct NS::A* get_A(void)
{
return (struct NS::A *) 0;
}

int main()
{

func(get_A(), 1);
}
//--------------------------------
END----------------------------------
This program compiles on g++ 4.12 but fails on g++ 2.95 with the
following error:

test.cpp: In function `int main()':
test.cpp:30: implicit declaration of function `int func(...)'

If I change the call from func(...) to NS::func(...), both the
compilers are happy. I can understand the reason for that. However,
how does the g++ 4.12 compiler build without explicitly specifying the
namespace?

Argument dependent lookup, a.k.a. ADL a.k.a Koenig lookup (after Andrew Koenig).

Since the type of the argument is "pointer to T" where T is defined in NS, the
overload set for the function includes matching declarations from NS.


Which is the correct behavior?

ADL.

It's great but it can get pretty tricky and yield unexpected results.

I would have liked for ADL to only apply to operators (where it's necessary),
but it applies to ordinarily named functions, sneaking in subtleties.


Cheers & hth.,

- Alf

PS: Comeau online, at <url: http://www.comeaucomputing.com/tryitout/>, is great
for checking out such snippets. And I did, since I was a little unsure about
"pointer to T" as opposed to just T. ADL is that subtle. It's sort of like
database hinting. Great when it just works, which is most of the time, but
correspondingly very ungreat when it doesn't work or doesn't work as expected.
 
A

Alan Woodland

Alf said:
* ks:

This should probably be a p-format.



Argument dependent lookup, a.k.a. ADL a.k.a Koenig lookup (after Andrew
Koenig).

Since the type of the argument is "pointer to T" where T is defined in
NS, the overload set for the function includes matching declarations
from NS.




ADL.

It's great but it can get pretty tricky and yield unexpected results.

I would have liked for ADL to only apply to operators (where it's
necessary), but it applies to ordinarily named functions, sneaking in
subtleties.
That has some advantages though for generic programming, allowing things
like sqrt, abs which live in the std namespace to work as expected for
user defined types without resorting to UB e.g.:

#include <cmath>
#include <iostream>

namespace thirdpartylib {
class MyBigInt { /* assume implict constructor for int and some
sensible int like operators */ };

MyBigInt sqrt(const MyBigInt&);
}

using std::sqrt;

template <typename T>
T doStuff(const T& a, const T& b) {
return sqrt((a - b) * (a - b));
}


int main() {
int a=1, b=2;
double c=1,d=2;
thirdpartlib::MyBigInt e=1,f=2;

std::cout << doStuff(a,b) << doStuff(c,d) << doStuff(e,f) << std::endl;

return 0;
}
 
A

Alf P. Steinbach

* Alan Woodland:
That has some advantages though for generic programming, allowing things
like sqrt, abs which live in the std namespace to work as expected for
user defined types without resorting to UB e.g.:

#include <cmath>
#include <iostream>

namespace thirdpartylib {
class MyBigInt { /* assume implict constructor for int and some
sensible int like operators */ };

MyBigInt sqrt(const MyBigInt&);
}

using std::sqrt;

template <typename T>
T doStuff(const T& a, const T& b) {
return sqrt((a - b) * (a - b));
}


int main() {
int a=1, b=2;
double c=1,d=2;
thirdpartlib::MyBigInt e=1,f=2;

std::cout << doStuff(a,b) << doStuff(c,d) << doStuff(e,f) << std::endl;

return 0;
}

No problem. Just place

thirdpartylib::MyBigInt sqrt( thirdpartylib::MyBigInt const& ) { ... }

in the global namespace. Since MyBigInt itself is safely down in a namespace
there's no overload collision.


Cheers,

- Alf (the campaign to *take back* the global namespace)
 
R

red floyd

Hi,

I have a problem with a piece of code. I'm in a situation where I have
to compile code using 2 different g++ compilers (2.95 and 4.12). I've
reduced the issue to a small, self contained program (given below)

Stop right there. 2.95 is ancient, dating from 2001. At the time,
they may not have
had ADL properly implemented.

I'd trust 4.12 rather than 2.95.
 
A

Alan Woodland

Alf said:
* Alan Woodland:
Alf said:
* ks: [snip]
Which is the correct behavior?
ADL.

It's great but it can get pretty tricky and yield unexpected results.

I would have liked for ADL to only apply to operators (where it's
necessary), but it applies to ordinarily named functions, sneaking in
subtleties.
That has some advantages though for generic programming, allowing things
like sqrt, abs which live in the std namespace to work as expected for
user defined types without resorting to UB e.g.:

#include <cmath>
#include <iostream>

namespace thirdpartylib {
class MyBigInt { /* assume implict constructor for int and some
sensible int like operators */ };

MyBigInt sqrt(const MyBigInt&);
}

using std::sqrt;

template <typename T>
T doStuff(const T& a, const T& b) {
return sqrt((a - b) * (a - b));
}


int main() {
int a=1, b=2;
double c=1,d=2;
thirdpartlib::MyBigInt e=1,f=2;

std::cout << doStuff(a,b) << doStuff(c,d) << doStuff(e,f) <<
std::endl;

return 0;
}

No problem. Just place

thirdpartylib::MyBigInt sqrt( thirdpartylib::MyBigInt const& ) { ... }

in the global namespace. Since MyBigInt itself is safely down in a
namespace there's no overload collision.

Hmm that's quite a good point. I wanted to debate this, but the only
half sane argument I can see against taking that approach would be
verbosity of compiler error messages when a call has no matching
overload, but has several close(ish) candidates. If everything is in the
global namespace the list you get back is potentially quite huge (try
for example something which doesn't have << for iostream with Qt, which
takes the global namespace approach).

Even that argument is mitigated by good tools (i.e. IDE) and potentially
ADL giving a shorter list could be unhelpful anyway. It still feels
dirty though as a library developer to be putting anything in the global
namespace.

Reminded me of an old GotW I read when I first encountered ADL:
http://www.gotw.ca/publications/mill02.htm

Alan
 
J

James Kanze


But note that it wasn't when one of his compilers (g++ 2.95)
appeared.

The C++ committee effectly defined a totally new language, only
vaguely based on C++ as we knew it back then. Try to write code
which works with such earlier compiler (e.g. g++ 2.95, VC++ 6)
is very trying.
It's great but it can get pretty tricky and yield unexpected results.
I would have liked for ADL to only apply to operators (where
it's necessary), but it applies to ordinarily named functions,
sneaking in subtleties.

The problem is that for many people, functions like sin and cos
are conceptually operators. If you're working on a mathematical
application, and you end up having to switch from double to
BigDouble, you'd be very peaved at having to write
ExtendedMath::sin(x), instead of just sin(x). Or even at having
to write "using ExtendedMath::sin", etc., for each of the
functions you're using. Especially if you're using the function
in a template function or class, that's sometimes instantiated
on double, and sometimes on ExtendedMath::BigDouble.

(Not that I disagree with you fundamentally. When the committee
realized that ADL, or something like it, would be necessary to
make namespaces usable, it should have simply decided that
namespaces weren't ripe, and dropped them for that version of
the standard.)
 
K

ks

But note that it wasn't when one of his compilers (g++ 2.95)
appeared.

The C++ committee effectly defined a totally new language, only
vaguely based on C++ as we knew it back then.  Try to write code
which works with such earlier compiler (e.g. g++ 2.95, VC++ 6)
is very trying.


The problem is that for many people, functions like sin and cos
are conceptually operators.  If you're working on a mathematical
application, and you end up having to switch from double to
BigDouble, you'd be very peaved at having to write
ExtendedMath::sin(x), instead of just sin(x).  Or even at having
to write "using ExtendedMath::sin", etc., for each of the
functions you're using.  Especially if you're using the function
in a template function or class, that's sometimes instantiated
on double, and sometimes on ExtendedMath::BigDouble.

(Not that I disagree with you fundamentally.  When the committee
realized that ADL, or something like it, would be necessary to
make namespaces usable, it should have simply decided that
namespaces weren't ripe, and dropped them for that version of
the standard.)

Thank you for all your replies. As I need this to work on both
compilers, I had to explcitly specify the NS::. However, I can see
that there are lot of different kinds of subtle bugs that can easily
creep in with ADL.
SK
 
J

Joshua Maurice

Thank you for all your replies. As I need this to work on both
compilers, [...]

Why? Perhaps there is a good reason, but I would question until I got
that good reason.
 
J

Jorgen Grahn

Stop right there. 2.95 is ancient, dating from 2001. At the time,
they may not have
had ADL properly implemented.

From 1999, actually. And yes, anyone having to use that one today has
a big problem.

Not that I blame him; I have to use a Sun compiler from the same era
for strange reasons. But I strongly suggest whining and begging to
move away from it.
I'd trust 4.12 rather than 2.95.

Except there is no such thing as gcc 4.12. He probably means 4.1.2
from 2007. Or something else entirely.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top