1、问题说明
项目中多个应用有跨语言跨平台的信息交互需求,因此选择了protobuf做协议编解码。在github上下载了2.7.0版本,根据安装说明编译后,编译失败,报如下错误:
./google/protobuf/metadata.h: In constructor ‘google::protobuf::internal::InternalMetadataWithArena::InternalMetadataWithArena(google::protobuf::Arena*)’:
./google/protobuf/metadata.h:174: 错误:类‘google::protobuf::internal::InternalMetadataWithArena’没有名为‘InternalMetadataWithArenaBase’的字段
./google/protobuf/metadata.h: In constructor ‘google::protobuf::internal::InternalMetadataWithArenaLite::InternalMetadataWithArenaLite(google::protobuf::Arena*)’:
./google/protobuf/metadata.h:203: 错误:类‘google::protobuf::internal::InternalMetadataWithArenaLite’没有名为‘InternalMetadataWithArenaBase’的字段
打开metadata.h文件查看后发现文件中定义了三个类,一个基类,两个派生类,如下所示(两派生类派生于同一基类,此处只选了一个):
template <class T, class Derived>
class InternalMetadataWithArenaBase {
public:
InternalMetadataWithArenaBase() : ptr_(NULL) {}
explicit InternalMetadataWithArenaBase(Arena* arena) : ptr_(arena) {}
~InternalMetadataWithArenaBase() {
if (have_unknown_fields() && arena() == NULL) {
delete PtrValue<Container>();
}
ptr_ = NULL;
}
//省略...
};
class InternalMetadataWithArena :
public InternalMetadataWithArenaBase<UnknownFieldSet, InternalMetadataWithArena> {
public:
InternalMetadataWithArena() {}
explicit InternalMetadataWithArena(Arena* arena) :
InternalMetadataWithArenaBase(arena) {} // !!!! error !!!!
void DoSwap(UnknownFieldSet* other) {
mutable_unknown_fields()->Swap(other);
}
//省略...
};
2、解决方案
查看编译错误信息,可以发现错误定位在派生类中由explicit修饰的构造函数处,编译器识别不出来初始化列表中用于初始化基类构造函数的符号。因此,可以从基类定义以及派生类对基类的使用两方面来查找错误原因。
该文件中,三个类的关系是两个普通类继承一个模板基类,而基类定义本身并无问题,就只能看使用了。由于派生类已经指明了模板参数,在派生类中引用模板基类,必须指明模板参数,否则编译器无法正确生成模板类的实例。将派生类红字处修改为如下形式后,编译通过。
附加说明:用explicit修饰单参数的构造函数,是为了告诉编译器该构造函数是显示的,不能利用它进行隐式的类型转换。
//...省略
explicit InternalMetadataWithArena(Arena* arena) :
InternalMetadataWithArenaBase<UnknownFieldSet, InternalMetadataWithArena>(arena) {} // !!!! OK !!!!
//...省略
3、编译环境
谷歌上传到github上的代码应该是经过测试的,所以推测是编译器的问题,可能使用高版本的编译器并无错误。
我这里的编译环境如下:
操作系统:RedHat 6.4 x86_64位(内核Linux data8 2.6.32-358.el6.x86_64)
GCC:gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC)
没有在更高版本的gcc上试过,可能模板语法在新版本的C++中已经有所变化吧,感兴趣的可以试试。
在使用 protobuf 2.7.0 版本进行跨语言跨平台信息交互时,遇到编译错误。问题集中在 metadata.h 文件中的派生类构造函数,编译器无法识别初始化基类构造函数的符号。解决方案是明确派生类中模板基类的模板参数,以避免编译器无法正确实例化模板类。在修复后,编译得以通过。

665

被折叠的 条评论
为什么被折叠?



