我正在尝试使用cmake
在Mac OS X中构建一个大项目,并遇到以下错误,我无法解决。
Archive.hpp:92:30: error: base specifier must name a class
struct Derived : T, Fallback { };
代码:
template<typename T>
class has_save_func
{
struct Fallback { int save; }; // add member name "X"
struct Derived : T, Fallback { };
...
此外,我有以下内容:
Archive.hpp:137:13: error: type 'unsigned long' cannot be used prior to '::'
代码:
template <class A>
static bool save(const A& data, class OutputArchive& oarchive, const std::string& id, typename boost::enable_if_c<has_save_func<A>::value, A>::type* def=NULL){
// todo check if A actually is friend with Access class, else return false
A::save(data, oarchive); // ! Error on this line !
return true;
}
template <class A>
static bool save(const A& data, class OutputArchive& oarchive, const std::string& id, typename boost::disable_if_c<has_save_func<A>::value, A>::type* def=NULL){
// todo check if A actually is friend with Access class, else return false
return serialization::save<A>( data, oarchive, id);
}
代码调用(OutputArchive.hpp):
template<class T>
void write(const T& data, const std::string& id){
// the data method must have an implementation of load/save and if not then we try the generic write
// method which could provide a solution by the implementation itself
writeEnterScope(id);
try {
Archive::Access::save<T>(data, *this, id);
} catch (...){
// we fall back to this call
boost::any adata(data);
write(adata, id);
}
writeLeaveScope(id);
}
Code serializeutil.cpp
void save(const rw::math::Q& tmp, OutputArchive& oar, const std::string& id){
oar.write(tmp.size(), "size");
for(int i=0;i<tmp.size();i++){
oar.write(tmp[i],"q");
}
}
编译器使用时会出现问题吗?
答案 0 :(得分:3)
两个错误都指向相同:您尝试将模板用于非类,很可能是unsigned int
。在第一种情况下,您将尝试从Derived
继承unsigned int
,这是非法的;在第二个中,您将尝试在save()
上调用静态方法(unsigned int
),这又是非法的。查看调用模板的代码可以澄清问题。
更新:从添加到问题的信息中我们现在可以得出结论,确实如此。 tmp.size()
,最有可能是unsigned int
,因此您使用oar.write()
致电unsigned int
;反过来,这会使用save()
调用unsigned int
,因此它会尝试调用unsigned int::save()
,这是非法的,并实例化类has_save_func<unsigned int>
,它会尝试定义{{1}这又是非法的。
如果您希望它们使用内置类型(例如struct Derived : unsigned int, Fallback
),我担心您需要重新设计类。您可以进行全面的重新设计,或者只是重载函数unsigned int
或write()
,具体取决于您的可用内容。
答案 1 :(得分:2)
我认为我可能要对提到的代码负责。但是有些东西不见了,多个人已经注意到了这一点。 OutputArchive上的重载写函数当前看起来像这样:
virtual void writeEnterScope(const std::string& id) = 0;
virtual void writeLeaveScope(const std::string& id) = 0;
virtual void writeEnterArray(const std::string& id) = 0;
virtual void writeLeaveArray(const std::string& id) = 0;
// writing primitives to archive
virtual void write(bool val, const std::string& id) = 0;
virtual void write(int val, const std::string& id) = 0;
virtual void write(unsigned int val, const std::string& id){ write((int)val,id); }
virtual void write(boost::uint64_t val, const std::string& id) = 0;
virtual void write(double val, const std::string& id) = 0;
virtual void write(const std::string& val, const std::string& id) = 0;
该软件的序列化部分尚未被使用,但无论如何它最终都在构建系统中。如果您在src / rwlibs中注释掉CMakeLists.txt中的serialize目录,那么它应该可以工作。或者为unsigned long添加一个write函数:
virtual void write(unsigned long val, const std::string& id){};
是的,在尝试创建另一个序列化框架之前,我确实研究过Boost.Serialization。然而,我试图创造一些不那么具有侵入性,模板化程度和用户友好性的东西....猜猜我失败了......
答案 2 :(得分:1)
首先,最好使用像Boost.Serialization这样的现有解决方案。它已经过调试,适用于您可能需要的所有情况。
但是,您仍然应该知道当前代码存在问题的位置以及如何执行此类模板机制。所以:
oar.write(tmp.size(), "size"); ^^^^^^^^^^
这是unsigned int
。你需要序列化它。所以你需要一个可以接受原始类型的写入。有两种选择:
为基本类型编写非模板重载。非模板重载优先于模板重载,因此如果使用unsigned int
第一个参数编写显式非模板重载,模板将不会被实例化,也不会出现任何错误。但是,您将需要分别为每种可能的基本类型重载,因为完全匹配的模板仍然比需要转换的非模板重载更受欢迎。
使用免费保存功能代替方法。方法的优点是它可以是虚拟的,但通常不需要使用模板。自由函数的优点是可以为非类类型定义它们,并且可以为已经存在的类定义它们,这两个类通常都需要在模板中使用。因此,您可以将save
方法的所有实例更改为自由函数,完全删除has_save_func
并为所需的基本类型重载save
函数。
修改has_save_func
,检查模板参数是否为类类型。非类型类型没有方法,因此这是其他变体将执行的操作。您可以使用boost::is_class或实现类似的功能。 Boost实际上通过枚举所有其他选项来实现它,但它也可以使用指向成员的指针来实现,这将在给定的非类型类型时引起SFINAE。不幸的是,当给定类类型时,你没有任何东西可以导致SFINAE,所以你必须结合功能模板和sizeof并最终得到非常棘手的东西(我敢肯定我已经看过了,但是真的不记得了)。