【问题标题】:Why do I get link errors when trying to create an instance of std::numpunct<char16_t> derivative?为什么在尝试创建 std::numpunct<char16_t> 导数的实例时会出现链接错误?
【发布时间】:2018-12-31 20:38:37
【问题描述】:

我正在尝试将std::basic_stringstream&lt;char16_t&gt; 与基于UTF16 的std::numpunct 结合使用。但是,即使尝试创建std::numpunct&lt;char16_t&gt; 的最简单可能的派生,也会在链接阶段失败。代码如下:

#include <locale>

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

int main()
{
    my_punct n;
}

这里是链接错误(使用 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

如果我将char16_t 更改为char,则链接成功完成。那么,我在这里做错了什么?我需要一些额外的库来链接吗?

作为健全性检查,我已尝试为_ZTVSt8numpunctIDsE grepping GCC 安装,但没有给出任何结果。但是寻找_ZTVSt8numpunctIcE 确实找到了libstdc++.so.6.0.24。这是否意味着我在 libstdc++ 中发现了一个错误?

【问题讨论】:

  • 看起来C++库只需要实现模板for char and wchar_t。对于char16_t,你运气不好,你的 C++ 库不支持它。
  • @SamVarshavchik 这将是一个更好的答案。

标签: c++ locale utf-16


【解决方案1】:

这是因为没有专门的类的支持实现。当您使用模板时会发生什么,编译器会为该特定用途生成一个符号。如果已经有一个预定义且完全模板化的实现,那么编译器可以做出自己的定义,但前提是它在编译文件试图使用它时看到模板化的实现。如果它看不到它,那么它只是创建符号,让它未定义,并期望稍后链接它。

举个简单的例子……

在 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”在内的任何东西都可以为任何试图使用模板的东西生成自己的实现。

如果您不拥有该模板,那么您能做的最好的事情就是找到一种方法来使用受支持的模板专业化。在这种情况下,最好将您的 char16_t 转换(或 typedef)为 short,然后看看是否可行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    相关资源
    最近更新 更多