「已注销」 2021-02-10 22:40 采纳率: 0%
浏览 573
已结题

使用clang++编译器,报错“Undefined Symbols”,如何解决?

编译一个代码后得到这样一个错误。

 

Undefined symbols for architecture x86_64:
  "A& A::operator<<=<int>(int)", referenced from:
      _main in main-fa1586.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

这个代码包括main.cpp,file.cpp,file.hpp这3个文件,其中main.cpp和file.cpp均有“#include "file.hpp"”。编译指令如下:

 

clang++ -o main main.cpp file.cpp

 

我使用的是mac版vscode环境,clang++编译器。发生这个错误后,我仔细检查,发现file.cpp中是包含这个函数的。于是觉得很奇怪,把这个函数的内容拷贝到了main.cpp,重新执行以上编译指令,居然发现编译通过了!我以为会报错,说函数重复定义。然后我把编译指令中的两个文件交换位置,结果仍然如此。我不知道为什么会这样,难道file.cpp中的函数定义编译器看不见吗?网上好像也没有解决问题的其他信息,希望了解的大佬尽快帮帮忙。

  • 写回答

3条回答 默认 最新

  • include_iostream_ 2021-02-11 13:17
    关注

    看起来你把模板函数声明和定义分开了,这是一个新手常犯的错误。**模板函数不是真正的函数,没有对应的汇编码,不会被真正编译**(类似地,模板类也不是真正的类),不能像普通函数那样分开声明和定义;完全特化后(简单说就是全部参数都被指定)的模板函数才是函数,具有对应的汇编码,能够被编译。

    这是模板函数的定义,**不是可编译的函数,只是提示编译器做基础的语法检查,不具有实际上的定义效力**:

    template <typename T>

    T foo(T x) { return x + 1; } // 由于T的类型不确定,这段代码不会在最终实际编译中体现出来,没有对应的可链接的符号

    这是模板函数的声明,**只能提示对应模板的存在,唯一的作用是让编译器能进行基本的语法检查**:

    template <typename T>

    T foo(T x);

    这是模板函数特化产生实例的调用,**可以提示编译器产生唯一确定的符号**:

    int a;

    a = foo(a);

    模板函数不能显式定义实例,而是要通过模板函数实例的调用提示编译符号后,编译器去找模板函数定义(请记住,模板函数定义只是对实际函数实例编译的提示,**并不具有实际上的定义效力**),去套这个模板产生函数实例,这个函数才真正产生了定义。如果模板函数定义在当前编译单元是不可见的(可以简单粗暴地认为,一个cpp文件就是一个编译单元。cpp文件所引用的头文件对这个编译单元当然也是可见的),模板函数就不能真正产生函数实例,对应的符号就会无法正确链接。一言以蔽之:未特化的模板是没有符号的,完全特化出来的函数实例才有符号。

    模板类的情况与此类似。

    =======================================

    说完了原因,我们来谈解决方案。

    现代编译器一般有全局优化功能(也有的称为链接时优化),可能能够解决问题。不过还有更稳妥的方案。

    方案一:老老实实把模板函数定义放进头文件里(因为模板函数定义不具有实际上的定义效力,这样做并不会产生符号重定义)。

    方案二:在file.cpp里,通过特化的模板函数声明(也即对函数实例进行声明)令编译器知道要产生一个int类型作为模板参数的函数实例,正确产生实例后就不应该再有链接问题。不过这样做的话,你就得对所有可能用得上的模板参数都进行类似的声明,其他类型就都不能套用这个模板了。

    我个人推荐方案一。

    如果还有问题或者我对问题理解有误的话,欢迎随时联系。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名