Почему я получаю ошибки ссылки при попытке создать экземпляр std :: numpunctпроизводная? - PullRequest
0 голосов
/ 31 декабря 2018

Я пытаюсь использовать std::basic_stringstream<char16_t> с std::numpunct на основе UTF16.Но попытка создать даже простейшую возможную производную std::numpunct<char16_t> терпит неудачу на этапе соединения.Вот код:

#include <locale>

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

int main()
{
    my_punct n;
}

А вот ошибки ссылок (при использовании g ++ 7.2.0) ( живой тест ):

$ 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

Если я изменю char16_t к char, соединение успешно завершено.Итак, что я здесь делаю не так?Нужна ли какая-то дополнительная библиотека для связи?

В качестве проверки работоспособности я попытался отключить установку GCC для _ZTVSt8numpunctIDsE, и она не дала результата.Но поиск для _ZTVSt8numpunctIcE нашел libstdc++.so.6.0.24.Означает ли это, что я нашел ошибку в libstdc ++?

1 Ответ

0 голосов
/ 01 января 2019

Это потому, что для специализированного класса не существует поддерживающей реализации.Когда вы используете шаблон, происходит то, что компилятор генерирует символ для этого конкретного использования.Если уже существует предопределенная и полностью шаблонная реализация, то компилятор может сделать свое собственное определение, но только если он видит шаблонную реализацию, когда компилирует файл, пытающийся его использовать.Если он не видит его, он просто создает символ, оставляет его неопределенным и ожидает связать его позже.

В качестве быстрого примера ...

в Template_Add.h

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

в Template_Add.cpp

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

в 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;
}

Причиной такого поведения является то, что нигде не существует шаблонной реализации, где main.cpp может ее увидеть.Однако, когда все связано, компоновщик видит, что «int add (int, int)» существует, и это разрешено.

Если вы владеете шаблоном, вы можете добавить (шаблонную) реализациюв .h файл, содержащий объявление шаблона.Таким образом, компилятор знает, как генерировать символ и определение во время компиляции.Чтобы исправить наш приведенный выше пример, мы могли бы добавить следующий код в Template_Add.h:

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

... и тогда все, включая «Template_Add.h», сможет генерировать свою собственную реализацию для всего, что пытаетсяиспользуйте шаблон.

Если вы не являетесь владельцем шаблона, лучшее, что вы можете сделать, - это найти способ использовать поддерживаемые специализации шаблона.В этом случае, возможно, было бы лучше привести (* или typedef) ваш char16_t в short, а затем посмотреть, работает ли он.

...