如何正确包含.h与.tpp文件?链接报错问题求助
链接错误原因及解决方法
问题场景
现有项目包含以下文件:
IOPinHandler.h
//IOPinHandler class //IOPinHandler.h #include <type_traits> class IOPin; //forward declaration required class IOPinHandler { public: explicit IOPinHandler() { } virtual ~IOPinHandler() { } void checkBool(const bool& b); void checkInt(const int& b); template<typename T> void modifyIOPinMember(IOPin& ioPin, const T& param); }; //To avoid multiple definitions #ifndef _OD_ void IOPinHandler::checkBool(const bool& b) { //Do stuff } void IOPinHandler::checkInt(const int& b) { //Do stuff } #endif
IOPinHandler.tpp
//IOPinHandler class //IOPinHandler.tpp template<typename T> void IOPinHandler::modifyIOPinMember(IOPin& ioPin, const T& param) { if constexpr(std::is_same_v<T, int>) { checkInt(param); ioPin.m2 = param; } else if constexpr(std::is_same_v<T, bool>) { checkBool(param); ioPin.m1 = param; } }
IOPin.h
//IOPin class //IOPin.h //To avoid multiple definitions #define _OD_ #include "IOPinHandler.h" class IOPin { public: explicit IOPin(const bool& b, const int& n):m1(b), m2(n) { _handler = new IOPinHandler; } void setInt(const int& n) { _handler->modifyIOPinMember(*this, n); } void setBool(const bool& b) { _handler->modifyIOPinMember(*this, b); } private: bool m1{false}; int m2{0}; IOPinHandler* _handler{nullptr}; friend class IOPinHandler; }; #include "IOPinHandler.tpp"
main.cpp
//main.cpp #include "IOPin.h" IOPin a(false, 0); int main() { a.setInt(89); a.setBool(true); return 0; }
编译运行时出现链接错误:
/usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<int>(IOPin&, int const&)': main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIiEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkInt(int const&)' /usr/bin/ld: /tmp/ccpKv7HW.o: in function `void IOPinHandler::modifyIOPinMember<bool>(IOPin&, bool const&)': main.cpp:(.text._ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_[_ZN12IOPinHandler17modifyIOPinMemberIbEEvR5IOPinRKT_]+0x27): undefined reference to `IOPinHandler::checkBool(bool const&)' collect2: error: ld returned 1 exit status
需求:不单独创建IOPinHandler.cpp文件的前提下解决该问题。
原因分析
问题出在_OD_宏的使用逻辑上:
- 当
IOPin.h包含IOPinHandler.h时,已经提前定义了_OD_,导致IOPinHandler.h中#ifndef _OD_条件不成立,checkBool和checkInt的函数定义完全没有被编译到任何目标文件中。 - 模板函数
modifyIOPinMember在main.cpp中被实例化时,会调用这两个函数,但链接器找不到对应的定义,因此抛出未定义引用错误。
你原本想用_OD_避免多重定义,但这个逻辑反而导致函数定义缺失。
解决方案
方案1:将函数定义改为inline(推荐)
在头文件中定义非模板函数时,使用inline关键字可以避免多重定义问题——编译器会将inline函数的定义纳入每个包含该头文件的编译单元,链接器会自动处理重复的inline函数定义。
修改IOPinHandler.h中的函数定义:
//IOPinHandler.h //... 类声明部分保持不变 ... inline void IOPinHandler::checkBool(const bool& b) { //Do stuff } inline void IOPinHandler::checkInt(const int& b) { //Do stuff } // 删除原来的#ifndef _OD_ 和 #endif 包裹代码
方案2:调整宏的使用逻辑
如果不想用inline,可以调整宏的定义时机,确保函数定义能被编译到至少一个编译单元中:
- 保留
IOPinHandler.h中#ifndef _OD_包裹的函数定义,但删除IOPin.h中提前定义的#define _OD_。 - 在某个单独的编译单元(比如
main.cpp)中,先定义_OD_再包含IOPinHandler.h,确保函数定义被编译一次。
但这种方式不如inline简洁直观,优先推荐方案1。
内容的提问来源于stack exchange,提问作者Juan_David
相关产品推荐
相关产品推荐

