unnamed namespace and friend method

J

John Ratliff

Can you declare a friend method if the method is defined in the unnamed
namespace?

This is basically what I'd like to do:

namespace {
MyClass *ptr;

void fnc(unsigned long my_ul, short *my_s_ptr) {
// blah blah whatever
ptr->callme();
}
}

class MyClass {
friend void fnc(unsigned long, short *);

private:
void callme();
}

g++ doesn't like this, but all is well if I put things in the global
namespace.

I suppose I could create a fake namespace, but before I do, can I do
what I want somehow? I also tried
friend void ::fnc(unsigned long, short *);
but that's no good either.

Thanks,

--John Ratliff
 
A

Alf P. Steinbach

* John Ratliff:
Can you declare a friend method if the method is defined in the unnamed
namespace?

This is basically what I'd like to do:

namespace {
MyClass *ptr;

void fnc(unsigned long my_ul, short *my_s_ptr) {
// blah blah whatever
ptr->callme();
}
}

class MyClass {
friend void fnc(unsigned long, short *);

private:
void callme();
}

g++ doesn't like this, but all is well if I put things in the global
namespace.

I suppose I could create a fake namespace, but before I do, can I do
what I want somehow? I also tried
friend void ::fnc(unsigned long, short *);
but that's no good either.

Why not make fnc a static member function.

Cheers, & hth.,

- Alf
 
J

John Ratliff

Alf said:
* John Ratliff:

Why not make fnc a static member function.

Sorry. I didn't mention what I was doing.

fnc is a callback used by a C-library. I was reading the FAQ on pointer
to members:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2

Q: How do I pass a pointer-to-member-function to a signal handler, X
event callback, system call that starts a thread/task, etc?

A: Don't.

re: static member functions

Something about name mangling and calling conventions. I'm hoping my
code will eventually work on Windows, Linux, and OS X even though right
now my sole target is Linux/g++.

--John Ratliff
 
A

Alf P. Steinbach

* John Ratliff:
Sorry. I didn't mention what I was doing.

fnc is a callback used by a C-library. I was reading the FAQ on pointer
to members:

http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2

Q: How do I pass a pointer-to-member-function to a signal handler, X
event callback, system call that starts a thread/task, etc?

A: Don't.

re: static member functions

Something about name mangling and calling conventions. I'm hoping my
code will eventually work on Windows, Linux, and OS X even though right
now my sole target is Linux/g++.

When you're passing function pointers you can forget about name
mangling, it's irrelevant.

Calling convention is a formal problem, but not a practical problem.

Anyway, if you want to avoid that little formal hurdle, why don't you
place the class in the anonymous namespace? Or, if the class is to be
exposed to other modules, but with the callback function not exposed,
consider using a namespace named MyClass_detail. Or, for example,
consider the PIMPL idiom.

An appropriate solution much depends on what your real issue is (as
opposed to attempted technical solution), and what you're willing to accept.

However, I'd go for the simple static member function, and simply say
that any compiler that doesn't give you a C-compatible calling
convention, if such should turn out to exist, just isn't good enough
(and chances are that for such a hypothetical compiler, there would be
some way to adjust the calling convention).

Cheers, & hth.,

- Alf
 
J

James Kanze

* John Ratliff:

[...]
When you're passing function pointers you can forget about
name mangling, it's irrelevant.
Calling convention is a formal problem, but not a practical
problem.

The fact that an `extern "C"' function has a different type is a
real, practical problem, since it means that trying to pass the
address of a static member won't compile with a compliant
compiler. Just because g++ and VC++ have a bug here doesn't
mean that all compilers do. (I get a diagnostic from Sun CC,
and I'm willing to bet that Comeau will give me one as well.)
However, I'd go for the simple static member function, and
simply say that any compiler that doesn't give you a
C-compatible calling convention, if such should turn out to
exist, just isn't good enough (and chances are that for such a
hypothetical compiler, there would be some way to adjust the
calling convention).

The problem isn't calling conventions, per se (although on an
Intel, I've actually encountered different convetions). The
problem is that the the linkage is part of the type, and that a
conformant compiler will enforce the type. And there are
conformant compilers around that do enforce it.
 
A

Alf P. Steinbach

* James Kanze:
* John Ratliff:
[...]
fnc is a callback used by a C-library. I was reading the FAQ
on pointer to members:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
Q: How do I pass a pointer-to-member-function to a signal handler, X
event callback, system call that starts a thread/task, etc?
A: Don't.
re: static member functions
Something about name mangling and calling conventions. I'm
hoping my code will eventually work on Windows, Linux, and
OS X even though right now my sole target is Linux/g++.
When you're passing function pointers you can forget about
name mangling, it's irrelevant.
Calling convention is a formal problem, but not a practical
problem.

The fact that an `extern "C"' function has a different type is a
real, practical problem, since it means that trying to pass the
address of a static member won't compile with a compliant
compiler. Just because g++ and VC++ have a bug here doesn't
mean that all compilers do. (I get a diagnostic from Sun CC,
and I'm willing to bet that Comeau will give me one as well.)

I don't know about Sun CC, but for Comeau, yes, by default in strict mode.

With Comeau, according to the online documentation, there is an option
"--implicit_extern_c_type_conversion" to allow this.

The test program I used with Comeau Online:

extern "C" void clibfunc( int (*)() ) {}

struct S
{
static int foo() { return 0; }
};

int main()
{
clibfunc( S::foo );
}

A workaround for Comeau, without using the compile option (since Comeau
Online only compiles there is a marginal chance that it emits some
information to the linker so that the linker could complain):

typedef int (*CallbackFunc)();

extern "C" void clibfunc( CallbackFunc ) {}


The problem isn't calling conventions, per se (although on an
Intel, I've actually encountered different convetions). The
problem is that the the linkage is part of the type, and that a
conformant compiler will enforce the type. And there are
conformant compilers around that do enforce it.

Hopefully it can also be turned off with Sun CC, e.g. as above.

Otherwise no way, as far as I can see, to avoid making a C callback
function extern linkage and global, visible throughout project...

The whole thing about calling conventions etc. is an unaddressed problem
in C++. The "extern C" syntax was probably meant to deal with it, but
doesn't, hence the large number of non-portable language extensions and
compiler options to deal with it. As I wrote, I think if a compiler
doesn't support such things, then it just isn't good enough. :)


Cheers,

- Alf
 
J

John Ratliff

When you're passing function pointers you can forget about name
mangling, it's irrelevant.

Calling convention is a formal problem, but not a practical problem.

Anyway, if you want to avoid that little formal hurdle, why don't you
place the class in the anonymous namespace? Or, if the class is to be
exposed to other modules, but with the callback function not exposed,
consider using a namespace named MyClass_detail. Or, for example,
consider the PIMPL idiom.

An appropriate solution much depends on what your real issue is (as
opposed to attempted technical solution), and what you're willing to
accept.

However, I'd go for the simple static member function, and simply say
that any compiler that doesn't give you a C-compatible calling
convention, if such should turn out to exist, just isn't good enough
(and chances are that for such a hypothetical compiler, there would be
some way to adjust the calling convention).

This has been very helpful, thank you.

I think I will use the static member function.

--John Ratliff
 
J

James Kanze

* James Kanze:

[...]
I don't know about Sun CC, but for Comeau, yes, by default in
strict mode.

As I expected. Comeau is generally closer to the standard than
most compilers.
With Comeau, according to the online documentation, there is
an option "--implicit_extern_c_type_conversion" to allow this.

Comeau uses the EDG front-end, and EDG is very, very good about
providing options to compile broken code which happened to work
with other compilers.
The test program I used with Comeau Online:
extern "C" void clibfunc( int (*)() ) {}
struct S
{
static int foo() { return 0; }
};
int main()
{
clibfunc( S::foo );
}
A workaround for Comeau, without using the compile option (since Comeau
Online only compiles there is a marginal chance that it emits some
information to the linker so that the linker could complain):
typedef int (*CallbackFunc)();
extern "C" void clibfunc( CallbackFunc ) {}

In other words, lie to the compiler. It will probably work,
because most linkers today are really pretty dumb.
Hopefully it can also be turned off with Sun CC, e.g. as above.

I rather doubt it, but I've not tried to.
Otherwise no way, as far as I can see, to avoid making a C
callback function extern linkage and global, visible
throughout project...

That's about the sum of it. You can put it in anonymous
namespace, but in practice, that doesn't mean much for an extern
"C" function.
The whole thing about calling conventions etc. is an
unaddressed problem in C++. The "extern C" syntax was
probably meant to deal with it, but doesn't, hence the large
number of non-portable language extensions and compiler
options to deal with it.

I'm not sure what you mean here. I've never used any
non-portable language extensions with regards to linkage. And
I've used compilers where C and C++ used different calling
conventions.
As I wrote, I think if a compiler doesn't support such things,
then it just isn't good enough. :)

For numerous reasons, compilers will continue to support broken
code. Even with Sun CC, it is just a warning (for now---the
message definitly indicates that it will become an error at some
time in the future). Still, there are definite reasons why
the standards committee added the linkage to the type. (I don't
think it was originally part of Stroustrup's intent, although
you'd have to ask him to be sure.)

Presumably, since it is part of the standard, other compilers
will add such checks in the future.
 
A

Alf P. Steinbach

* James Kanze:
I'm not sure what you mean here. I've never used any
non-portable language extensions with regards to linkage.

Hm. OK, lets agree on terminology first, that "linkage", for the
purpose of this discussion, includes not only external, internal and
none, but also what the standard calls "language linkage". Which is not
very well defined, but presumably is meant to include such things as
data representation, calling convention and name mangling (these last
two are mentioned by the standard), which in turn determines whether
type information is communicated across translation units.

Now let's say you're using some abstract binary interface (ABI) that
imposes a particular data representation, calling convention and name
mangling. This is very common. In Windows programming the most common
such ABI is named COM (Common Object Model or whatever current acronym).

The 'extern "C"' syntax only standardizes strings for general C and C++
language linkage. This is useless when there is more than one possible
combination of calling convention and name mangling for each language,
and it lumps together things that shouldn't be. So the compiler must
use non-standard strings and a non-standard naming scheme (hopefully not
a specific name for each combination!) if it is to use this syntax.

In practice, Windows compilers let the name mangling scheme be
determined by the language name (C or C++) and the calling convention,
and use de-facto standard language extensions for the calling convention.

If the 'extern' syntax had standardized a little more variation than
just C versus C++, in particular the three most common calling
conventions for free functions (or better, stack versus register
passing, and for stack, right-left versus left-right plus who cleans up,
for a total of five), and placed less emphasis on being a means to
specify language and more emphasis on being a means to specify calling
convention and name mangling, this mess could have been avoided.

And
I've used compilers where C and C++ used different calling
conventions.

I presume you don't mean the situation when compiling the C++ code with
switches to use calling convention 1, and the C code with the same
compiler with switches to use calling convention 2, or with some
unrelated C compiler?

Do you mind clarifying which compiler(s) this was?

For numerous reasons, compilers will continue to support broken
code.

No, on the contrary. The code is Right (TM), expressing what one needs.
The language, offering no formally correct way to do what's right and
needed and established practice (to have an 'extern "C"' type compatible
function that is not in the global namespace), is Broken (TM). :)

Even with Sun CC, it is just a warning (for now---the
message definitly indicates that it will become an error at some
time in the future). Still, there are definite reasons why
the standards committee added the linkage to the type. (I don't
think it was originally part of Stroustrup's intent, although
you'd have to ask him to be sure.)

Presumably, since it is part of the standard, other compilers
will add such checks in the future.

Let's hope they make the warning very optional...


Cheers,

- Alf
 

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

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,807
Latest member
ryef

Latest Threads

Top