Query: How to declare a template class member function 'extern "C"' ?

T

tropostropos

On Solaris, using the Sun compiler, I get annoying warnings from the
following code. The problem is that I am passing a C++ member function
pointer to the C library function qsort. Is there a solution?
Declaring the function extern "C" fails, because linkage declarations
must be made at file scope.

#include <stdlib.h> //for qsort

template <class T>
class Sorter
{
public:

//CompareVector is passed to qsort, which requires a C function
pointer parameter.
//extern "C" { static int CompareVector (t void *otPt1, const void
*otPt2;} //Wont compile!
static int CompareVector (const void *otPt1, const void *otPt2);
//Gets warning!
void InternalSort ();

T **vptPoints;
int viNumPoints;

};


template <class T>
void Sorter<T>::InternalSort ()
{
qsort( vptPoints, viNumPoints, sizeof (T*), CompareVector
); //last param should be extern "C"!
}

template <class T>
int Sorter<T>::CompareVector (const void *otPt1, const void *otPt2)
{
return 0; //We don't bother executing it: toy code to fix
compilation warning.
}

int main()
{

Sorter<int> s;
s.InternalSort();

}
 
G

Greg

On Solaris, using the Sun compiler, I get annoying warnings from the
following code. The problem is that I am passing a C++ member function
pointer to the C library function qsort. Is there a solution?
Declaring the function extern "C" fails, because linkage declarations
must be made at file scope.

#include <stdlib.h> //for qsort

template <class T>
class Sorter
{
public:

//CompareVector is passed to qsort, which requires a C function
pointer parameter.
//extern "C" { static int CompareVector (t void *otPt1, const void
*otPt2;} //Wont compile!
static int CompareVector (const void *otPt1, const void *otPt2);
//Gets warning!
void InternalSort ();

T **vptPoints;
int viNumPoints;

};


template <class T>
void Sorter<T>::InternalSort ()
{
qsort( vptPoints, viNumPoints, sizeof (T*), CompareVector
); //last param should be extern "C"!
}

template <class T>
int Sorter<T>::CompareVector (const void *otPt1, const void *otPt2)
{
return 0; //We don't bother executing it: toy code to fix
compilation warning.
}

int main()
{

Sorter<int> s;
s.InternalSort();

}

As long as the program tries to use a member function pointer as a
callback routine, it will never be able to run correctly.

Member function pointers cannot be used as callback routines because an
instance of the class is always needed in order to call the member
function through a pointer. Qsort has no instance of a class Sorter<T>
handy, so it has no way of calling CompareVector to make the
comparison.

Even if qsort had an instance of a Sorter, it would still not be able
to invoke the callback correctly. There is a mismatch in the argument
lists of the two routines: CompareVector accepts three parameters,
while the qsort callback takes two only. Now it may appear that I
miscounted: CompareVector's declaration certainly looks like only two
arguments are accepted. But when counting parameters, we must also
count the hidden, "this" parameter passed to member functions. Qsort
knows nothing about this parameter, so not only would the "this"
parameter be missing from qsort's argument list passed to the callback,
the two parameters that it did include would be shifted over one
register from the location where CompareVector expects to find them.

Given that the classes involved in the sort operation are templates, I
would suggest looking at std::sort instead of qsort as an easier, more
C++ solution to the problem.

Greg
 
T

tropostropos

The code as it stands generates the following warning:

"test.cpp", line 22: Warning (Anachronism): Formal argument 4 of type
extern "C" int(*)(const void*,const void*) in call to std::qsort(void*,
unsigned, unsigned, extern "C" int(*)(const void*,const void*)) is
being passed int(*)(const void*,const void*).
"test.cpp", line 35: Where: While instantiating
"Sorter<int>::InternalSort()".
"test.cpp", line 35: Where: Instantiated from non-template code.
1 Warning(s) detected.

If I comment out the declaration labelled "Gets Warning!" and I
un-comment-out the declaration labelled "Wont compile!", then I get the
following errors:

"test.cpp", line 21: Error: InternalSort() is not a member of
Sorter<T>.
"test.cpp", line 27: Error: CompareVector(const void*, const void*) is
not a member of Sorter<T>.
"test.cpp", line 9: Error: Linkage specifications are allowed only at
file level.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: storage class extern not allowed for a
member.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: A declaration does not specify a tag or an
identifier.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: Use ";" to terminate declarations.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: "}" expected instead of "{".
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 35: Error: InternalSort is not a member of
Sorter<int>.
8 Error(s) detected.
 
B

benben

On Solaris, using the Sun compiler, I get annoying warnings from the
following code. The problem is that I am passing a C++ member function
pointer to the C library function qsort. Is there a solution?
Declaring the function extern "C" fails, because linkage declarations
must be made at file scope.

#include <stdlib.h> //for qsort

template <class T>
class Sorter
{
public:

//CompareVector is passed to qsort, which requires a C function
pointer parameter.
//extern "C" { static int CompareVector (t void *otPt1, const void

What is "t void" supposed to be?
 
B

benben

As long as the program tries to use a member function pointer as a
callback routine, it will never be able to run correctly.

The OP declared his callback function static, which is fine for callback.
The problem is the compiler error with extern "C", which is a thing for
linkers and I don't think it is needed.

Ben
 
B

benben

I don't think the extern "C" is needed. I am not sure but I guess it merely
tells the compiler to emit C function symbol (as opposed to the mangled C++
symbol) for linking.

Otherwise consider sharing a non-template base and make the actual
comparison virtual, then retrofit a global (extern "C") function to wrap the
virtual call.

Ben
 
A

Alf P. Steinbach

* benben:
The OP declared his callback function static, which is fine for callback.

No, it isn't.

Some compilers allow it, in the same way they (or should I say, MSVC) allow
'int main'.

That doesn't make it valid C++.

The problem is the compiler error with extern "C", which is a thing for
linkers and I don't think it is needed.

It is needed.

The solution in this case and most other cases is to do things at the C++
level instead of the C level, i.e., here, to use std::sort.
 
T

tropostropos

A reply to Greg's comment that <<we must also count the hidden, "this"
parameter passed to member functions.>> :

But static member functions (like CompareVector) do not have a hidden
"this" parameter pointing to an instance, and no instance is required
to invoke a static member function. So that should not be a problem
for qsort.

I suspect that C++ simply does not permit member functions to have "C"
linkage. So what is the simplest workaround?
 
W

wkaras

The code as it stands generates the following warning:

"test.cpp", line 22: Warning (Anachronism): Formal argument 4 of type
extern "C" int(*)(const void*,const void*) in call to std::qsort(void*,
unsigned, unsigned, extern "C" int(*)(const void*,const void*)) is
being passed int(*)(const void*,const void*).
"test.cpp", line 35: Where: While instantiating
"Sorter<int>::InternalSort()".
"test.cpp", line 35: Where: Instantiated from non-template code.
1 Warning(s) detected.

If I comment out the declaration labelled "Gets Warning!" and I
un-comment-out the declaration labelled "Wont compile!", then I get the
following errors:

"test.cpp", line 21: Error: InternalSort() is not a member of
Sorter<T>.
"test.cpp", line 27: Error: CompareVector(const void*, const void*) is
not a member of Sorter<T>.
"test.cpp", line 9: Error: Linkage specifications are allowed only at
file level.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: storage class extern not allowed for a
member.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: A declaration does not specify a tag or an
identifier.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: Use ";" to terminate declarations.
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 9: Error: "}" expected instead of "{".
"test.cpp", line 34: Where: While specializing "Sorter<int>".
"test.cpp", line 34: Where: Specialized in non-template code.
"test.cpp", line 35: Error: InternalSort is not a member of
Sorter<int>.
8 Error(s) detected.

This file:
=========================

#include <stdlib.h>

class A
{
public:
int i[100];
static int cmp(const void *v1, const void *v2)
{ return(* (int *) v1 - * (int *) v2); }
};

void foo(A &a) { qsort(a.i, 100, sizeof(a.i[0]), A::cmp); }

==========================
compiles without warnings using GCC (on Solaris). Whether
or not the class is templeted should be irrelevant.

I guess the point of the warnings your compiler is giving
is that the code would not be portable to an environment
where the C and C++ compilers use different calling conventions.
But I'm not sure that the Standard allows for linkage specifiers
to trigger the use of different calling conventions in the
object code.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top