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

Discussion in 'C++' started by tropostropos@hotmail.com, Aug 3, 2005.

  1. Guest

    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, 2005
    #1
    1. Advertising

  2. WittyGuy Guest

    Will you please post the warnings/errors as reported by the compiler?

    -Wg-
    WittyGuy, Aug 3, 2005
    #2
    1. Advertising

  3. Greg Guest

    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
    Greg, Aug 3, 2005
    #3
  4. Guest

    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, 2005
    #4
  5. benben Guest

    <> wrote in message
    news:...
    > 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();
    >
    > }
    >
    benben, Aug 3, 2005
    #5
  6. benben Guest


    > 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
    benben, Aug 3, 2005
    #6
  7. benben Guest

    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
    benben, Aug 3, 2005
    #7
  8. * 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?
    Alf P. Steinbach, Aug 3, 2005
    #8
  9. Guest

    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, 2005
    #9
  10. Guest

    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, 2005
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon G Best
    Replies:
    2
    Views:
    418
    Simon G Best
    Sep 25, 2003
  2. kid_kei
    Replies:
    1
    Views:
    733
    Alf P. Steinbach
    May 12, 2006
  3. =?gb2312?B?wfXquw==?=
    Replies:
    10
    Views:
    685
    Victor Bazarov
    Aug 1, 2007
  4. Replies:
    2
    Views:
    655
    Triple-DES
    Feb 26, 2008
  5. Peng Yu
    Replies:
    3
    Views:
    756
    Thomas J. Gritzan
    Oct 26, 2008
Loading...

Share This Page