Why do I get link errors when trying to create an instance of std::numpunct derivative?












2















I'm trying to make use of std::basic_stringstream<char16_t> with a UTF16-based std::numpunct. But an attempt to create even the simplest possible derivative of std::numpunct<char16_t> fails at link stage. Here's the code:



#include <locale>

struct my_punct : public std::numpunct<char16_t> {};

int main()
{
my_punct n;
}


And here are link errors (using g++ 7.2.0) (live test):



$ g++-7 test0.cpp -o test
/tmp/cc0oWPhL.o: In function `std::numpunct<char16_t>::numpunct(unsigned int)':
test0.cpp:(.text._ZNSt8numpunctIDsEC2Ej[_ZNSt8numpunctIDsEC5Ej]+0x36): undefined reference to `std::numpunct<char16_t>::_M_initialize_numpunct(__locale_struct*)'
/tmp/cc0oWPhL.o: In function `my_punct::~my_punct()':
test0.cpp:(.text._ZN8my_punctD2Ev[_ZN8my_punctD5Ev]+0x18): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0x8): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0xc): undefined reference to `std::numpunct<char16_t>::~numpunct()'
collect2: error: ld returned 1 exit status


If I change char16_t to char, linking completes successfully. So, what am I doing wrong here? Do I need some additional library to link against?



As a sanity check, I've tried grepping GCC installation for _ZTVSt8numpunctIDsE, and it gave no result. But grepping for _ZTVSt8numpunctIcE did find libstdc++.so.6.0.24. Does this mean I've found a bug in libstdc++?










share|improve this question


















  • 2





    It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

    – Sam Varshavchik
    Dec 31 '18 at 20:42











  • @SamVarshavchik this would be better as an answer.

    – Ruslan
    Dec 31 '18 at 21:39
















2















I'm trying to make use of std::basic_stringstream<char16_t> with a UTF16-based std::numpunct. But an attempt to create even the simplest possible derivative of std::numpunct<char16_t> fails at link stage. Here's the code:



#include <locale>

struct my_punct : public std::numpunct<char16_t> {};

int main()
{
my_punct n;
}


And here are link errors (using g++ 7.2.0) (live test):



$ g++-7 test0.cpp -o test
/tmp/cc0oWPhL.o: In function `std::numpunct<char16_t>::numpunct(unsigned int)':
test0.cpp:(.text._ZNSt8numpunctIDsEC2Ej[_ZNSt8numpunctIDsEC5Ej]+0x36): undefined reference to `std::numpunct<char16_t>::_M_initialize_numpunct(__locale_struct*)'
/tmp/cc0oWPhL.o: In function `my_punct::~my_punct()':
test0.cpp:(.text._ZN8my_punctD2Ev[_ZN8my_punctD5Ev]+0x18): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0x8): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0xc): undefined reference to `std::numpunct<char16_t>::~numpunct()'
collect2: error: ld returned 1 exit status


If I change char16_t to char, linking completes successfully. So, what am I doing wrong here? Do I need some additional library to link against?



As a sanity check, I've tried grepping GCC installation for _ZTVSt8numpunctIDsE, and it gave no result. But grepping for _ZTVSt8numpunctIcE did find libstdc++.so.6.0.24. Does this mean I've found a bug in libstdc++?










share|improve this question


















  • 2





    It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

    – Sam Varshavchik
    Dec 31 '18 at 20:42











  • @SamVarshavchik this would be better as an answer.

    – Ruslan
    Dec 31 '18 at 21:39














2












2








2








I'm trying to make use of std::basic_stringstream<char16_t> with a UTF16-based std::numpunct. But an attempt to create even the simplest possible derivative of std::numpunct<char16_t> fails at link stage. Here's the code:



#include <locale>

struct my_punct : public std::numpunct<char16_t> {};

int main()
{
my_punct n;
}


And here are link errors (using g++ 7.2.0) (live test):



$ g++-7 test0.cpp -o test
/tmp/cc0oWPhL.o: In function `std::numpunct<char16_t>::numpunct(unsigned int)':
test0.cpp:(.text._ZNSt8numpunctIDsEC2Ej[_ZNSt8numpunctIDsEC5Ej]+0x36): undefined reference to `std::numpunct<char16_t>::_M_initialize_numpunct(__locale_struct*)'
/tmp/cc0oWPhL.o: In function `my_punct::~my_punct()':
test0.cpp:(.text._ZN8my_punctD2Ev[_ZN8my_punctD5Ev]+0x18): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0x8): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0xc): undefined reference to `std::numpunct<char16_t>::~numpunct()'
collect2: error: ld returned 1 exit status


If I change char16_t to char, linking completes successfully. So, what am I doing wrong here? Do I need some additional library to link against?



As a sanity check, I've tried grepping GCC installation for _ZTVSt8numpunctIDsE, and it gave no result. But grepping for _ZTVSt8numpunctIcE did find libstdc++.so.6.0.24. Does this mean I've found a bug in libstdc++?










share|improve this question














I'm trying to make use of std::basic_stringstream<char16_t> with a UTF16-based std::numpunct. But an attempt to create even the simplest possible derivative of std::numpunct<char16_t> fails at link stage. Here's the code:



#include <locale>

struct my_punct : public std::numpunct<char16_t> {};

int main()
{
my_punct n;
}


And here are link errors (using g++ 7.2.0) (live test):



$ g++-7 test0.cpp -o test
/tmp/cc0oWPhL.o: In function `std::numpunct<char16_t>::numpunct(unsigned int)':
test0.cpp:(.text._ZNSt8numpunctIDsEC2Ej[_ZNSt8numpunctIDsEC5Ej]+0x36): undefined reference to `std::numpunct<char16_t>::_M_initialize_numpunct(__locale_struct*)'
/tmp/cc0oWPhL.o: In function `my_punct::~my_punct()':
test0.cpp:(.text._ZN8my_punctD2Ev[_ZN8my_punctD5Ev]+0x18): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0x8): undefined reference to `std::numpunct<char16_t>::~numpunct()'
/tmp/cc0oWPhL.o:(.rodata._ZTVSt8numpunctIDsE[_ZTVSt8numpunctIDsE]+0xc): undefined reference to `std::numpunct<char16_t>::~numpunct()'
collect2: error: ld returned 1 exit status


If I change char16_t to char, linking completes successfully. So, what am I doing wrong here? Do I need some additional library to link against?



As a sanity check, I've tried grepping GCC installation for _ZTVSt8numpunctIDsE, and it gave no result. But grepping for _ZTVSt8numpunctIcE did find libstdc++.so.6.0.24. Does this mean I've found a bug in libstdc++?







c++ locale utf-16






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 31 '18 at 20:38









RuslanRuslan

5,80533373




5,80533373








  • 2





    It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

    – Sam Varshavchik
    Dec 31 '18 at 20:42











  • @SamVarshavchik this would be better as an answer.

    – Ruslan
    Dec 31 '18 at 21:39














  • 2





    It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

    – Sam Varshavchik
    Dec 31 '18 at 20:42











  • @SamVarshavchik this would be better as an answer.

    – Ruslan
    Dec 31 '18 at 21:39








2




2





It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

– Sam Varshavchik
Dec 31 '18 at 20:42





It looks like the C++ library is only required to implement the template for char and wchar_t. For char16_t, you're out of luck, and it's not supported by your C++ library.

– Sam Varshavchik
Dec 31 '18 at 20:42













@SamVarshavchik this would be better as an answer.

– Ruslan
Dec 31 '18 at 21:39





@SamVarshavchik this would be better as an answer.

– Ruslan
Dec 31 '18 at 21:39












1 Answer
1






active

oldest

votes


















1














It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.



As a quick example...



in Template_Add.h



// Generic template
template< class T >
T add(T first, T second);


in Template_Add.cpp



// Specialized for int
template<>
int add<int>(int first, int second){


in main.cpp



#include "Template_Add.h"

int main(){
int ia, ib, ic;
double da, db, dc;

ia = 3;
ib = 4;

da = 3.0;
db = 4.0;


// we expect ia = 7, and works
ic = add(ib, ic);

// we expect dc = 7.0, but doesn't work
// this will result in an unresolved symbol
dc = add(da, db);

return 0;
}


The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.



If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:



template< class T >
T add(T first, T second){
return first + second;
}


...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.



If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53991243%2fwhy-do-i-get-link-errors-when-trying-to-create-an-instance-of-stdnumpunctchar%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.



    As a quick example...



    in Template_Add.h



    // Generic template
    template< class T >
    T add(T first, T second);


    in Template_Add.cpp



    // Specialized for int
    template<>
    int add<int>(int first, int second){


    in main.cpp



    #include "Template_Add.h"

    int main(){
    int ia, ib, ic;
    double da, db, dc;

    ia = 3;
    ib = 4;

    da = 3.0;
    db = 4.0;


    // we expect ia = 7, and works
    ic = add(ib, ic);

    // we expect dc = 7.0, but doesn't work
    // this will result in an unresolved symbol
    dc = add(da, db);

    return 0;
    }


    The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.



    If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:



    template< class T >
    T add(T first, T second){
    return first + second;
    }


    ...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.



    If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.






    share|improve this answer






























      1














      It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.



      As a quick example...



      in Template_Add.h



      // Generic template
      template< class T >
      T add(T first, T second);


      in Template_Add.cpp



      // Specialized for int
      template<>
      int add<int>(int first, int second){


      in main.cpp



      #include "Template_Add.h"

      int main(){
      int ia, ib, ic;
      double da, db, dc;

      ia = 3;
      ib = 4;

      da = 3.0;
      db = 4.0;


      // we expect ia = 7, and works
      ic = add(ib, ic);

      // we expect dc = 7.0, but doesn't work
      // this will result in an unresolved symbol
      dc = add(da, db);

      return 0;
      }


      The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.



      If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:



      template< class T >
      T add(T first, T second){
      return first + second;
      }


      ...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.



      If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.






      share|improve this answer




























        1












        1








        1







        It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.



        As a quick example...



        in Template_Add.h



        // Generic template
        template< class T >
        T add(T first, T second);


        in Template_Add.cpp



        // Specialized for int
        template<>
        int add<int>(int first, int second){


        in main.cpp



        #include "Template_Add.h"

        int main(){
        int ia, ib, ic;
        double da, db, dc;

        ia = 3;
        ib = 4;

        da = 3.0;
        db = 4.0;


        // we expect ia = 7, and works
        ic = add(ib, ic);

        // we expect dc = 7.0, but doesn't work
        // this will result in an unresolved symbol
        dc = add(da, db);

        return 0;
        }


        The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.



        If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:



        template< class T >
        T add(T first, T second){
        return first + second;
        }


        ...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.



        If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.






        share|improve this answer















        It's because there isn't a supporting implementation for the specialized class. What happens when you utilize a template is that the compiler generates a symbol for that particular use. If there is already a predefined and fully templated implementation, then the compiler can make its own definition, but only if it sees the templated implementation when it compiles the file trying to use it. If it can't see it, then it just creates the symbol, leaves it undefined, and expects to link it later.



        As a quick example...



        in Template_Add.h



        // Generic template
        template< class T >
        T add(T first, T second);


        in Template_Add.cpp



        // Specialized for int
        template<>
        int add<int>(int first, int second){


        in main.cpp



        #include "Template_Add.h"

        int main(){
        int ia, ib, ic;
        double da, db, dc;

        ia = 3;
        ib = 4;

        da = 3.0;
        db = 4.0;


        // we expect ia = 7, and works
        ic = add(ib, ic);

        // we expect dc = 7.0, but doesn't work
        // this will result in an unresolved symbol
        dc = add(da, db);

        return 0;
        }


        The reason for this behavior is that there isn't a templated implementation that exists anywhere where main.cpp can see it. When everything is linked, however, the linker sees that an "int add(int, int)" exists, and so that is allowed.



        If you own the template, then you can add the (templated) implementation into the .h file containing the template declaration. That way the compiler knows how to generate the symbol and definition at compile time. To fix our above example, we could add the following code to Template_Add.h:



        template< class T >
        T add(T first, T second){
        return first + second;
        }


        ...and then anything including "Template_Add.h" would be able to generate its own implementation for anything trying to make use of the template.



        If you don't own the template, then the best you can do is find a way to use the supported template specializations. In this case, it might be best to cast (or typedef) your char16_t into a short, and then see if that works.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 31 '18 at 21:25

























        answered Dec 31 '18 at 21:20









        andrewecandrewec

        898




        898
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53991243%2fwhy-do-i-get-link-errors-when-trying-to-create-an-instance-of-stdnumpunctchar%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Mossoró

            Error while reading .h5 file using the rhdf5 package in R

            Pushsharp Apns notification error: 'InvalidToken'