1

我正在尝试在 Mac OS X 中构建一个大型项目,cmake但遇到了以下我无法解决的错误。

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");
    }
}

我使用的编译器可能有问题吗?

4

3 回答 3

3

这两个错误都指向相同:您正在尝试将模板与非类一起使用,很可能是unsigned int. 在第一种情况下,您将尝试Derived继承 from unsigned int,这是非法的;在第二种情况下,您将尝试在 上调用静态方法 ( save()) unsigned int,这又是非法的。查看调用模板的代码将澄清问题。

更新:从添加到问题的信息中,我们现在可以得出结论,情况确实如此。tmp.size(), 很可能是一个unsigned int, 所以你oar.write()用一个unsigned int; 反过来, thissave()用 an调用unsigned int,因此它尝试调用unsigned int::save()非法的 ,并实例化 class has_save_func<unsigned int>,它试图struct Derived : unsigned int, Fallback再次定义哪个是非法的。

如果您希望它们使用内置类型(例如unsigned int. 您可能会进行完全重新设计或只是重载函数write()save(),这取决于您有什么可用的。

于 2012-10-02T08:03:10.843 回答
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 中的序列化目录,那么它应该可以工作。或者为 unsigned long 添加一个写入函数:

virtual void write(unsigned long val, const std::string& id){};

是的,在冒险创建另一个序列化框架之前,我确实研究了 Boost.Serialization。然而,我试图创建一些不那么侵入性、更少模板化和更用户友好的东西......我猜我失败了......

于 2012-10-04T12:02:26.063 回答
1

First, it would be better to use existing solution like Boost.Serialization. It's already debugged and works in all the cases you may need.

However, you should still know where your current code has problems and how to do template machinery like this. So:

oar.write(tmp.size(), "size");
          ^^^^^^^^^^

This is unsigned int. And you do need to serialize it. So you need a write, that can accept primitive types. There are two options:

  1. Write non-template overloads for primitive types. Non-template overloads have priority over template ones, so if you write explicit non-template overload with unsigned int first argument, the template won't be instantiated and there won't be any error. You will however need overloads for each possible primitive type separately, because template that matches exactly will be still preferred over non-template overload that requires conversion.

  2. Use free save function instead of method. Advantage of method is that it can be virtual, but you don't usually need that with template. Advantages of free function are that they can be defined for non-class types and that they can be defined for already existing classes, both of which you often do need in templates. So you would change all instances of the save method to free function, drop the has_save_func altogether and overload the save function for primitive types you need.

  3. Amend the has_save_func with check whether the template argument is a class type. Non-class types don't have methods, so that's what the other variant will do. You can either use the boost::is_class or implement something similar. Boost actually implements it by enumerating all the other options, but it can also be implemented using pointer-to-member, which will cause SFINAE when given non-class type. Unfortunately you don't have anything to cause SFINAE when given class type, so you have to combine with function templates and sizeof and end up with really tricky stuff (I'm sure I've seen it, but really don't remember it).

于 2012-10-02T08:50:07.917 回答