CentOS8用GCC8编译旧程序时boost::asio::strand无参数列表错误如何解决
问题根源
你遇到的报错本质是CentOS 8自带的Boost版本远高于CentOS 6的版本:Boost.Asio从1.70版本开始重构了Executor模型,原来的非模板类boost::asio::strand被改成了需要显式指定Executor类型的模板类template<class Executor> boost::asio::strand,你用的旧版redisclient库是基于老版本Boost开发的,自然不兼容高版本Boost的接口。
另外你切换到C17不生效的原因是:类模板参数推导只能用于函数内变量定义(构造时传参推导),你这个是类成员变量声明,没有初始化参数给编译器推导模板类型,所以开C17也解决不了问题。
可行解决方案(均不需要修改第三方库代码)
方案1:降级安装兼容的低版本Boost
最稳妥的方案,安装和CentOS 6上版本一致的Boost(比如1.53/1.58版本,只要是strand还未改为模板的版本即可),安装时指定独立路径比如/opt/boost-old避免覆盖系统Boost,然后修改你的Makefile:
# 假设低版本Boost安装在/opt/boost-old CXXFLAGS = -O2 -std=c++11 -I/opt/boost-old/include LDFLAGS = -L/opt/boost-old/lib -Wl,-rpath=/opt/boost-old/lib all: my_prog my_prog: my_prog.o g++ $(LDFLAGS) my_prog.o -o my_prog -lboost_filesystem -lboost_system -lsecond_level_include -lthird_level_include -lboost_regex -lboost_program_options `mysql_config --libs`
编译运行时都会优先用你安装的低版本Boost,不会和系统高版本冲突。
方案2:注入兼容头文件补全旧接口
如果你不想换Boost版本,可以用GCC的-include参数强制注入兼容代码,完全不需要修改第三方库源码:
- 新建一个
fix_boost_strand.hpp文件,内容如下:
#include <boost/asio/io_service.hpp> #include <boost/asio/strand.hpp> namespace boost { namespace asio { // 补全旧版本非模板strand的类型定义 typedef strand<io_service::executor_type> strand; } // namespace asio } // namespace boost
- 修改Makefile的CXXFLAGS,增加
-include fix_boost_strand.hpp参数:
CXXFLAGS = -O2 -std=c++11 -include fix_boost_strand.hpp
这个参数会让GCC在编译所有源文件前,先引入你写的兼容头,相当于给高版本Boost补了旧版本的strand类型别名,直接兼容旧redisclient的代码。
方案3:用预定义宏直接替换类型
如果不想额外加头文件,也可以直接在编译参数里加宏定义替换,修改CXXFLAGS如下:
CXXFLAGS = -O2 -std=c++11 -D"boost::asio::strand=boost::asio::strand<boost::asio::io_service::executor_type>"
效果和注入头文件一致,就是把代码里所有的boost::asio::strand直接替换为实例化后的模板类型。
内容的提问来源于stack exchange,提问作者Lucky

