Topic: Template functions and extern "C"?
Author: tannhauser86549spam@free.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Sat, 11 Sep 2004 02:04:38 GMT Raw View
A few days ago, during a discussion in fr.comp.lang.c++, the question
arose whether a template function can be 'extern "C"'.
Even if the language syntax doesn't seem to allow declaring such a
function directly, a declaration through a typedef would be possible.
First example:
______________________________________________________________
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T>
struct wrap_pthreadEntry
{
static pthreadEntryFunc externCfunc; // declaration
};
template<typename T>
void* wrap_pthreadEntry<T>::externCfunc(void* p) // definition
{
return static_cast<T*>(p)->memfunc();
}
______________________________________________________________
Here, the standard =A7 7.5/4 is very clear: "A C language linkage is
ignored for the names of class members and the member function type of
class member functions." and the example given thereafter in that
paragraph, although showing a non-templated class, is analogous to
the above code.
However, how about this one:
_________________________________________________________________________=
__
#include <iostream>
#include <ostream>
extern "C" typedef void* pthreadEntryFunc(void*);
template<typename T> pthreadEntryFunc threadStarter; // declaration
template<typename T> void* threadStarter( void* p ) // definition
{
return static_cast<T*>( p )->memfunc() ;
}
struct foo
{
foo* memfunc() { std::cout << "foo" << std::endl; return this; }
};
struct bar
{
bar* memfunc() { std::cout << "bar" << std::endl; return this; }
};
extern "C"
{
void* (*pf)(void*) =3D 0;
}
void* toto(void* p) { return p; } // extern "C++" by default
int main()
{
pf =3D &threadStarter<foo>; // Refused by Dinkum[VC++/C++], accepted by
// g++, Comeau and Dinkum[EDG/C++] (refused by the two latter if
// the template function declaration above is suppressed)
pf =3D &threadStarter<bar>; // Same as above
#if 0
// Standard conformance check:
pf =3D &toto; // Accepted by g++ and Dinkum[VC++/C++], refused (correct=
ly,
// according to the standard) by Comeau and Dinkum[EDG/C++]
#endif
return 0;
}
_________________________________________________________________________=
__
I'm aware that that the linkage specification 'extern "C"' influences 2
different potential sources of incompatibility: name mangling (support
type-safe linkage and overloading in C++) and calling convention (paramet=
er
passing on stack / in registers, in which order / alignment, stack cleanu=
p
by caller or callee, return value passing...). Name mangling prevents lin=
king
a "C" call against a C++ function symbol definition but would not affect
a call from "C" of a C++ function through a pointer. However, different
calling conventions prevent correct calls even through pointers, which is
why the C++ standard makes the linkage specification part of the function
type so that an assignment of an 'extern "C++"' function to an 'extern "C=
"'
function pointer becomes a 'type mismatch' error. (On compilers using
compatible calling conventions, it may make sense to allow said assignmen=
t
as a non-conforming, non-portable extension.)
Interesting enough, neither compiler accepts
namespace A { extern "C" void haha() {} }
namespace B { extern "C" void haha() {} }
which means they all correctly detect duplicate symbols, and consequently=
,
they do mangle the template function name provided they compile it.
My question: Which one of the compilers I tested is right? Should the cod=
e
above compile, and should the template instantiations always be correctly
callable from "C" through a pointer - let's say, would they be a valid
argument for pthread_create, providing it with a type-safe wrapper :-)?
Falk Tannh=E4user
---
[ 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.jamesd.demon.co.uk/csc/faq.html ]