
[英]Using child class as a template parameter of a base class and as a nested name specifier
[英]Build error: base specifier must name a class
我正在尝试使用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);
}
代码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");
}
}
编译器即时通讯可能会出现问题吗?
两种错误都指向相同的位置:您尝试将模板与非类(很可能是unsigned int
。 在第一种情况下,您将尝试让Derived
从unsigned int
继承,这是非法的。 在第二种方法中,您将尝试在unsigned int
上调用静态方法( save()
),这又是非法的。 查看调用模板的代码可以弄清问题。
更新:从添加到问题的信息中,我们现在可以得出结论,确实如此。 tmp.size()
很可能是一个unsigned int
,因此您要使用一个unsigned int
调用oar.write()
; 反过来,这会使用unsigned int
调用save()
,因此它尝试调用unsigned int::save()
,这是非法的,并实例化类has_save_func<unsigned int>
,该类试图定义struct Derived : unsigned int, Fallback
是非法的。
恐怕如果您希望类与内置类型(例如unsigned int
一起使用,则需要重新设计类。 您可能要进行完全的重新设计,或者只是重载函数write()
或save()
,具体取决于可用的功能。
我认为我可能要为上述代码负责。 但是缺少一些东西,许多人已经注意到了这一点。 当前看起来像这样的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中注释掉序列化目录,则它应该可以工作。 或为无符号长型添加写功能:
virtual void write(unsigned long val, const std::string& id){};
是的,在尝试创建另一个序列化框架之前,我确实研究过Boost.Serialization。 但是,我正在尝试创建一种不那么麻烦,更少模板化且更加用户友好的东西。
首先,最好使用Boost.Serialization之类的现有解决方案。 它已经调试,可以在您可能需要的所有情况下使用。
但是,您仍然应该知道当前代码在哪里有问题以及如何进行这样的模板处理。 所以:
oar.write(tmp.size(), "size"); ^^^^^^^^^^
这是unsigned int
。 而且您确实需要对其进行序列化。 因此,您需要一个可以接受原始类型的写入。 有两种选择:
为原始类型编写非模板重载。 非模板重载的优先级高于模板重载的优先级,因此,如果您使用unsigned int
first参数编写显式非模板重载,则模板不会被实例化,也不会出现任何错误。 但是,您将分别需要每种可能的原始类型的重载,因为与需要转换的非模板重载相比,精确匹配的模板仍然是首选。
使用免费保存功能代替方法。 方法的优点是它可以是虚拟的,但通常不需要模板。 自由函数的优点是可以为非类类型定义它们,也可以为已经存在的类定义它们,而您经常在模板中都需要这两个类。 因此,您可以将save
方法的所有实例更改为free函数,完全删除has_save_func
并为所需的基本类型重载save
函数。
修改has_save_func
并检查template参数是否为类类型。 非类类型没有方法,因此其他变体将这样做。 您可以使用boost :: is_class或实现类似的东西。 Boost实际上通过枚举所有其他选项来实现它,但是它也可以使用指向成员的指针来实现,这在给定非类类型时会导致SFINAE。 不幸的是,当给定类类型时,您没有任何导致SFINAE的东西,因此您必须将其与函数模板和sizeof结合使用,并最终获得非常棘手的东西(我确定我已经看过它,但真的不记得了) )。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.