By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,782 Members | 1,154 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,782 IT Pros & Developers. It's quick & easy.

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

P: n/a
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();

}

Aug 3 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Will you please post the warnings/errors as reported by the compiler?

-Wg-

Aug 3 '05 #2

P: n/a
tr**********@hotmail.com wrote:
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

Aug 3 '05 #3

P: n/a
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.

Aug 3 '05 #4

P: n/a

<tr**********@hotmail.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...
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?

*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();

}

Aug 3 '05 #5

P: n/a
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
Aug 3 '05 #6

P: n/a
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
Aug 3 '05 #7

P: n/a
* 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.


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.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Aug 3 '05 #8

P: n/a
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?

Aug 3 '05 #9

P: n/a
tr**********@hotmail.com wrote:
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.

Aug 3 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.