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 intDerived最初のケースでは、から継承しようとしますがunsigned int、これは違法です。save()2番目の例では、で静的メソッド( )を呼び出そうとしますがunsigned int、これも不正です。テンプレートを呼び出すコードを見ると、問題が明らかになります。

更新:質問に追加された情報から、これは確かに事実であると結論付けることができます。tmp.size()、はおそらく、であるため、 ;unsigned intで呼び出しoar.write()ています。unsigned intこれは、次に、を使用して呼び出すため、違法であるを呼び出しようとしsave()、クラスをインスタンス化して、どちらが再び違法であるかを定義しようとします。unsigned intunsigned int::save()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のserializeディレクトリをコメントアウトすると、機能するはずです。または、unsignedlongの書き込み関数を追加します。

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

そして、はい、私はさらに別のシリアル化フレームワークを作成する前に、Boost.Serializationを調べました。しかし、私は邪魔にならず、テンプレート化されておらず、よりユーザーフレンドリーなものを作成しようとしていました....私はそれに失敗したと思います...

于 2012-10-04T12:02:26.063 に答える
1

まず、 Boost.Serializationなどの既存のソリューションを使用することをお勧めします。すでにデバッグされており、必要なすべてのケースで機能します。

ただし、現在のコードに問題がある場所と、このようなテンプレート機構を実行する方法を知っておく必要があります。それで:

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

これはunsigned intです。そして、あなたはそれをシリアル化する必要があります。したがって、プリミティブ型を受け入れることができる書き込みが必要です。2つのオプションがあります。

  1. プリミティブ型の非テンプレートオーバーロードを記述します。非テンプレートのオーバーロードはテンプレートのオーバーロードよりも優先されるため、最初の引数を使用して明示的な非テンプレートのオーバーロードを記述した場合unsigned int、テンプレートはインスタンス化されず、エラーは発生しません。ただし、変換が必要な非テンプレートのオーバーロードよりも完全に一致するテンプレートの方が優先されるため、可能なプリミティブ型ごとに個別にオーバーロードが必要になります。

  2. メソッドの代わりに無料の保存機能を使用してください。メソッドの利点は、仮想化できることですが、通常、テンプレートでは必要ありません。free関数の利点は、クラス以外の型に対して定義できることと、既存のクラスに対して定義できることです。どちらも、テンプレートで必要になることがよくあります。したがって、メソッドのすべてのインスタンスを関数を解放するように変更し、完全saveに削除して、必要なプリミティブ型の関数をオーバーロードします。has_save_funcsave

  3. has_save_funcテンプレート引数がクラス型であるかどうかをチェックして修正します。非クラス型にはメソッドがないため、他のバリアントはそれを実行します。boost :: is_classを使用するか、同様のものを実装できます。Boostは実際には他のすべてのオプションを列挙することで実装しますが、メンバーへのポインターを使用して実装することもできます。これにより、非クラス型が指定された場合にSFINAEが発生します。残念ながら、クラスタイプが指定されたときにSFINAEを引き起こすものは何もないので、関数テンプレートとsizeofを組み合わせて、本当にトリッキーなものにする必要があります(私はそれを見たと確信していますが、実際には覚えていません)。

于 2012-10-02T08:50:07.917 に答える