Topic: Templates and extern "C
Author: Ross Smith <ross.s@ihug.co.nz>
Date: Thu, 12 Jul 2001 21:06:07 GMT Raw View
John Michael Davison wrote:
>
> Ross Smith <ross.s@ihug.co.nz> wrote in message news:<3B27E1D2.860A213A@ihug.co.nz>...
>
> > I wanted a way to easily generate a family of callback functions (not a
> > single "generic pointer" for all of them, which seems to be what you're
> > implying above). I'll explain the context in more detail.
>
> The workaround you describe relies on a closure pointer.
> "pthread_create" is nice enough to provide one, but you
> certainly can't rely on legacy APIs to provide one.
I don't understand what you mean. Could you amplify please?
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Unix has always lurked provocatively in the background of the operating
system wars, like the Russian Army." -- Neal Stephenson
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: jdavison@speakeasy.org (John Michael Davison)
Date: Fri, 13 Jul 2001 13:10:51 GMT Raw View
I wrote:
>The workaround [described by Ross Smith] relies on a closure pointer.
>"pthread_create" is nice enough to provide one, but you certainly
can't rely
>on legacy APIs to provide one.
Ross Smith <"ross.s@ihug.co.nz"> wrote in message news:<3B4E0E5F.41956CD0@ihug.co.nz>:
>I don't understand what you mean. Could you amplify please?
Say that I have a class template static member function "void
*X<T>::foo(void *)" in a class template X<T>. Inside the definition
of class
template X<T>, I have code that passes "&X<T>::foo" to a function,
such as
pthread_create (see URL
"http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_create.html"),
which
expects 'extern "C" void *(*)(void *)'.
Because ISO/IEC 14882:1998 forbids me to declare a class
template
static member function with "extern C" linkage, I can't do this.
Instead, I have to wrap "&X<T>::foo" with a function that has
extern
"C" linkage. Let's create a function -- call it "callback_function"
-- to do
it. Your example does that. In order to register this callback
function, I
have to provide two pieces of information: the address of
"callback_function"
_and_ a companion datum that "callback_function" will use in order to
determine
exactly what function my wrapper must dispatch.
The third argument to "pthread_create" is for the address of
"callback_function"; The fourth argument, "arg", is the closure
pointer.
("Closure" is a mathematical term that was appropriated by the LISP
community.) If "pthread_create" didn't have the closure pointer, it
would be
impossible to convey the companion datum to "callback_function".
To ensure reentrancy in general, a callback function must have
two data
passed to it: call-specific data (information relevant to whatever
event
prompted that specific callback invocation) and the "closure" data,
i.e.
information that was supplied at the time of registration. If no
mechanism for
conveying closure are provided, you might be able to get away with
thread-specific data, but that won't solve the problem in all cases.
(It might
work for "qsort" if you weren't planning to use it reentrantly, but it
certainly wouldn't work for "pthread_create" if the latter didn't
provide a
closure pointer.)
Examples of callback registration functions missing a
provision for
closure are "std::qsort", "std::signal", "std::set_new_handler",
"std::set_unexpected", "std::set_terminate", and the POSIX "sigaction"
function. (In my opinion, "qsort" should have been designed with a
closure
pointer from Day One. The "std::new_handler",
"std::unexpected_handler", and
"std::terminate_handler" types should have been defined as abstract
classes.)
It just so happens that Pthreads doesn't pass a "call-specific
data"
argument to its "pthread_create" callbacks, but "pthread_create" is an
anomaly:
most libraries are not in a position to provide data specific to a
particular
invocation of a callback function via a function. Pthreads can do so
through
the "pthread_self" function only because "pthread_self" provides its
call-specific information through an implementation-specific
mechanism.
Everyone else has to pass call-specific data.
C++ callbacks are typically implemented via functors since
they address
the closure problem more elegantly than a closure pointer, but you
can't use that with a callback mechanism defined in C. The best you
can do
with a C interface is to encode the functor via a "callback_function"
wrapper
and decode it within "callback_function". You can't do this
reentrantly
without hijacking the closure pointer, using it to store the functor
address.
If one's original (pre-ISO/IEC 14882:1998) C++ code made use
of a
C-style function, you have to convert it to something like the
following in
order to pass the user's closure pointer along:
struct CallBackDescriptor
{
FunctorDescriptor(
CStyleFunctiuon *callback_function,
void *closure) :
callback_function_(callback_function),
closure_(closure_),
{
}
CStyleFunction *callback_function_;
void * cb_closure_;
};
Your wrapper function will look something like the following:
extern "C"
CStyleFunctionReturnType
callback_function(CallData *call_data, void *closure)
{
const CallBackDescriptor * const call_ptr =
reinterpret_cast<CallbackFunctor *>(closure);
return (*call_ptr->callback_function)(
call_data, call_ptr->cb_closure);
}
...and, of course, in addition to worrying about the scope and
lifetime of the
closure data passed in by the user, you also get to worry about the
scope and
lifetime of the associated CallBackDescriptor. A strict, consistent
ownership discipline is advised.
There's plenty of code like this out there that needs to be
converted
in this way in order to conform to ISO/IEC 14882:1998. Most C++
programs that
link to the X Toolkit have to be modified in the above manner.
Anyway, getting back to templates...
In my opinion, the inability to generate an extern "C"-linkage
function
from a template is a serious design flaw in ISO/IEC 14882:1998 that
must be
addressed in the next standard.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: jdavison@speakeasy.org (John Michael Davison)
Date: Thu, 12 Jul 2001 19:37:59 GMT Raw View
Ross Smith <ross.s@ihug.co.nz> wrote in message news:<3B27E1D2.860A213A@ihug.co.nz>...
> I wanted a way to easily generate a family of callback functions (not a
> single "generic pointer" for all of them, which seems to be what you're
> implying above). I'll explain the context in more detail.
The workaround you describe relies on a closure pointer.
"pthread_create" is nice enough to provide one, but you
certainly can't rely on legacy APIs to provide one.
No reentrant workaround exists.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "Noah Stein" <noah@vision-scape.com>
Date: Mon, 25 Jun 2001 17:12:07 GMT Raw View
I can't cite chapter and verse because my ANSI spec is on my home machine,
not my work one. But I can give you a reason that the template functions
cannot follow the naming scheme you suggest: "*", "<", and ">" are
specifically not allowed in function names.
No C or C++ parser will correctly tokenize "foo<thing>"; it comes out of the
parser as a foo-token a less-than-token, a thing-token, and a greater-than
token. To make a change to support that would mandate an
intervening-whitespace rule in the grammar. Such a change would result in
massive incompatibilities with prior code for no great reason.
To use your routines in C, you'll have to explicitly instantiate the
routines you need. How difficult is it then to add something along the
following lines:
extern "C" void foo_int()
{
foo<int>();
}
If you've specified foo<>() as inline, on most compilers you won't take a
single cycle of performance penalty. It's marginally more complex than any
other method of ensuring a template function instantiation. And it doesn't
require changing a single rule of the spec.
My $0.02.
-- Noah
"Ross Smith" <ross.s@ihug.co.nz> wrote in message
news:3B26D536.237DF40B@ihug.co.nz...
> Francis Glassborow wrote:
> >
> > In article <3B269D17.C59B7E07@ihug.co.nz>, Ross Smith
> > <ross.s@ihug.co.nz> writes
> > >Why is that a problem? Different instantiations have different names --
> > >foo<int>, foo<char*>, etc.
> >
> > There are no such names in C.
>
> Again: Why is that a problem? There's no requirement, as far as I know,
> that a function declared extern "C" has to be callable _by name_ from
> actual C code. In the situation that prompted my original post, I wanted
> an easy way to generate a family of callback functions.
>
> James Kuyper tells me that foo is the "real" function name and foo<int>
> is something else called a "template-id", which doesn't make much sense
> to me. I guess this is another of those weird gratuitous differences
> between function and class templates.
>
> I'd still like someone to point out the chapter and verse on this.
>
> --
> Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
> ========================================================================
> "Hungarian notation is the tactical nuclear weapon of
> source code obfuscation techniques." -- Roedy Green
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Luc Van Oostenryck <luc.vanoostenryck@easynet.be>
Date: Thu, 14 Jun 2001 20:53:29 GMT Raw View
Ross Smith wrote:
>
> Where does the standard say that function templates can't be extern "C"?
> All three compilers I tried it on (MSVC 6, GCC 2.95.3, and the Comeau
> online test drive) agree that it isn't allowed, but I can't find
> anything in the standard that forbids it. Can anyone quote chapter and
> verse on this?
>
> --
> Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
> ========================================================================
> "Hungarian notation is the tactical nuclear weapon of
> source code obfuscation techniques." -- Roedy Green
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
What name will you use in your C code when you use these functions ?
--
Luc Van Oostenryck
Do not use the address in the 'reply-to' field, but this instead:
<luc dot vanoostenryck at easynet dot be>
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Wed, 13 Jun 2001 15:57:32 GMT Raw View
Ross Smith <ross.s@ihug.co.nz> writes:
| James Kuyper tells me that foo is the "real" function name and foo<int>
| is something else called a "template-id", which doesn't make much sense
| to me.
I agree with you: "foo" is certainly -not- the "real" function name;
foo<int> is the "real" function name.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 13 Jun 2001 17:42:48 GMT Raw View
In article <3B26D536.237DF40B@ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>Again: Why is that a problem? There's no requirement, as far as I know,
>that a function declared extern "C" has to be callable _by name_ from
>actual C code. In the situation that prompted my original post, I wanted
>an easy way to generate a family of callback functions.
Callbacks from code written in C? :)
Now let me see if, joking apart, I understand the problem. You need to
generate generic pointers to functions with extern "C" linkage? Now, of
the cuff, I do not know how to do that, but once we understand the
problem, rather than a solution that does not work we have a chance to
solve it.
Rather than speculate, let us wait a little to see if one of the library
specialists already has a solution to your problem.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: Wed, 13 Jun 2001 22:01:03 GMT Raw View
Francis Glassborow wrote:
>
> Now let me see if, joking apart, I understand the problem. You need to
> generate generic pointers to functions with extern "C" linkage? Now, of
> the cuff, I do not know how to do that, but once we understand the
> problem, rather than a solution that does not work we have a chance to
> solve it.
I wanted a way to easily generate a family of callback functions (not a
single "generic pointer" for all of them, which seems to be what you're
implying above). I'll explain the context in more detail.
(The code that follows is just off the top of my head and probably
buggy, but it's along the same general lines as the real situation.)
Consider a generic thread class, with an interface something like this:
class Thread {
public:
template <typename T> Thread(T& t);
};
(and a bunch of other functions, but only the constructor is relevant to
all this.) T is a function-object type; the Thread constructor calls t's
operator() in a separate thread.
My current implementation uses a technique similar to (a very simplified
version of) Andrei Alexandrescu's generalised functor (I invented the
technique independently some time ago; I've always called it the "mixed
metaphor idiom", since it combines OO and generic techniques). Something
like this:
class CallbackBase {
public:
virtual ~CallbackBase() {}
virtual void run() = 0;
};
extern "C" void* callback_function(void* ptr) {
CallbackBase* call_ptr = static_cast<CallbackBase*>(ptr);
call_ptr->run();
delete call_ptr;
return 0;
}
class Thread {
private:
template <typename T> class Callback: public CallbackBase {
public:
Callback(T& t): t_(t) {}
virtual void run() { t_(); }
private:
T& t_;
};
public:
template <typename T> Thread(T& t) {
CallbackBase* callback = new Callback<T>(t);
pthread_create(&thread_, 0, callback_function, callback);
}
private:
pthread_t thread_;
};
If I could have extern "C" templates, it could all be made a lot
simpler:
template <typename T> extern "C" void* callback_function(void* ptr) {
T* t_ptr = static_cast<T*>(ptr);
(*t_ptr)();
return 0;
}
class Thread {
public:
template <typename T> Thread(T& t) {
pthread_create(&thread_, 0, callback_function<T>, &t);
}
private:
pthread_t thread_;
};
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Hungarian notation is the tactical nuclear weapon of
source code obfuscation techniques." -- Roedy Green
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: Tue, 12 Jun 2001 21:13:24 GMT Raw View
Where does the standard say that function templates can't be extern "C"?
All three compilers I tried it on (MSVC 6, GCC 2.95.3, and the Comeau
online test drive) agree that it isn't allowed, but I can't find
anything in the standard that forbids it. Can anyone quote chapter and
verse on this?
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Hungarian notation is the tactical nuclear weapon of
source code obfuscation techniques." -- Roedy Green
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 12 Jun 2001 22:07:40 GMT Raw View
In article <3B259570.7E87531E@ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>Where does the standard say that function templates can't be extern "C"?
>All three compilers I tried it on (MSVC 6, GCC 2.95.3, and the Comeau
>online test drive) agree that it isn't allowed, but I can't find
>anything in the standard that forbids it. Can anyone quote chapter and
>verse on this?
I think it is a side effect of the requirement that an extern "C"
function must be unique (i.e., it can be overloaded with functions of
the same name and other linkages - with distinct parameter sets, but you
can only have a single use of a function name with C linkage)
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: Tue, 12 Jun 2001 22:56:50 GMT Raw View
Francis Glassborow wrote:
>
> In article <3B259570.7E87531E@ihug.co.nz>, Ross Smith
> <ross.s@ihug.co.nz> writes
> >Where does the standard say that function templates can't be extern "C"?
> >All three compilers I tried it on (MSVC 6, GCC 2.95.3, and the Comeau
> >online test drive) agree that it isn't allowed, but I can't find
> >anything in the standard that forbids it. Can anyone quote chapter and
> >verse on this?
>
> I think it is a side effect of the requirement that an extern "C"
> function must be unique (i.e., it can be overloaded with functions of
> the same name and other linkages - with distinct parameter sets, but you
> can only have a single use of a function name with C linkage)
Why is that a problem? Different instantiations have different names --
foo<int>, foo<char*>, etc.
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Hungarian notation is the tactical nuclear weapon of
source code obfuscation techniques." -- Roedy Green
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Wed, 13 Jun 2001 01:12:49 GMT Raw View
Ross Smith wrote:
>
> Francis Glassborow wrote:
> >
> > In article <3B259570.7E87531E@ihug.co.nz>, Ross Smith
> > <ross.s@ihug.co.nz> writes
> > >Where does the standard say that function templates can't be extern "C"?
> > >All three compilers I tried it on (MSVC 6, GCC 2.95.3, and the Comeau
> > >online test drive) agree that it isn't allowed, but I can't find
> > >anything in the standard that forbids it. Can anyone quote chapter and
> > >verse on this?
> >
> > I think it is a side effect of the requirement that an extern "C"
> > function must be unique (i.e., it can be overloaded with functions of
> > the same name and other linkages - with distinct parameter sets, but you
> > can only have a single use of a function name with C linkage)
>
> Why is that a problem? Different instantiations have different names --
> foo<int>, foo<char*>, etc.
No - those aren't function names, those are template-ids. They all share
the same function name, "foo".
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 13 Jun 2001 02:25:36 GMT Raw View
In article <3B269D17.C59B7E07@ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>Why is that a problem? Different instantiations have different names --
>foo<int>, foo<char*>, etc.
There are no such names in C.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: Wed, 13 Jun 2001 12:23:29 GMT Raw View
Francis Glassborow wrote:
>
> In article <3B269D17.C59B7E07@ihug.co.nz>, Ross Smith
> <ross.s@ihug.co.nz> writes
> >Why is that a problem? Different instantiations have different names --
> >foo<int>, foo<char*>, etc.
>
> There are no such names in C.
Again: Why is that a problem? There's no requirement, as far as I know,
that a function declared extern "C" has to be callable _by name_ from
actual C code. In the situation that prompted my original post, I wanted
an easy way to generate a family of callback functions.
James Kuyper tells me that foo is the "real" function name and foo<int>
is something else called a "template-id", which doesn't make much sense
to me. I guess this is another of those weird gratuitous differences
between function and class templates.
I'd still like someone to point out the chapter and verse on this.
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Hungarian notation is the tactical nuclear weapon of
source code obfuscation techniques." -- Roedy Green
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]