Boost Asio模板Socket类实例化报asio::ip::basic_endpoint未定义引用求解
错误根因
这是C++模板的经典链接错误:模板类/函数的实现不能拆分到独立的.cpp文件中(除非做显式实例化)。编译ApplicationMain.cpp时,编译器仅能看到Socket.h里的模板声明,看不到Socket.cpp里的实现,无法生成Socket<boost::asio::ip::tcp::endpoint>对应的构造函数实例,最终链接时报未定义引用。
解决方法
提供两种常用方案:
方案1:模板实现移入头文件(最推荐)
把Socket.cpp里的构造函数实现直接放到Socket.h中,删除独立的Socket.cpp文件即可。修改后的Socket.h代码如下:
// Socket.h #include <boost/asio.hpp> template <typename T> class Socket { private: // 注意:当前mAcceptor是tcp专属类型,要兼容udp的话需要同步调整该成员类型 boost::asio::ip::tcp::acceptor mAcceptor; public: Socket(boost::asio::io_service& ioService, T ep); }; // 实现移到头文件内 template <typename T> Socket<T>::Socket(boost::asio::io_service& ioService, T ep): mAcceptor(ioService, ep) { }
编译指令调整为:
g++ ApplicationMain.cpp -lboost_system -lpthread -lboost_thread -o output.out
方案2:显式实例化模板
如果一定要保留模板实现和头文件分离的结构,需要在Socket.cpp末尾显式声明你会用到的所有模板实例类型:
// Socket.cpp 末尾新增 template class Socket<boost::asio::ip::tcp::endpoint>; // 后续如果要用到udp endpoint,再加一行:template class Socket<boost::asio::ip::udp::endpoint>;
这种方案的缺点是每新增一种模板参数类型,都需要手动添加实例化声明,灵活性差。
额外注意
你当前的Socket类成员mAcceptor是boost::asio::ip::tcp::acceptor类型,仅支持tcp的endpoint,就算模板参数传入udp endpoint也会编译报错。如果要真正兼容tcp/udp两种类型,需要同步把成员变量的类型也改为和模板参数关联的泛型类型。
内容的提问来源于stack exchange,提问作者Rosh
相关产品推荐
相关产品推荐

