2016-03-30 10 views
1

コンテキストと抽象型の割り当てを避ける:私はブーストからのアーカイブの同様の方法で、データのアーカイブのためのいくつかのツールを書きました。テンプレート

class A 
{ 
    private: 
    double a; 
    public: 
    A() : a(3.14159) 
    {} 
    A(const A& a_) : a(a_.a) {} 
    virtual ~A() 
    {} 
    virtual A* clone() const = 0; // Then, A is virtual 

    virtual void save(O_Archive& oa) const // 
    {          // 
     oa << this->a;      // INTERESTING 
    }          // PART OF THE 
    virtual void load(I_archive& ia)  // CLASS 
    {          // 
     ia >> this->a;      // 
    }          // 
}; 
O_Archive& operator << (O_Archive& oa, const A& a) 
{ 
    a.save(oa); 
    return oa; 
} 
I_Archive& operator >> (I_Archive& ia, A& a) 
{ 
    a.load(ia); 
    return ia; 
} 

class B : public A 
{ 
    private: 
    double b; 
    public: 
    B() : A(), b(1.0) {} 
    B(const B& b_) : A(b_), b(b_.b) {} 
    virtual ~B() {} 
    virtual A* clone() const 
    { 
     return new B(*this); 
    } 

    void save(O_Archive& oa) const // 
    {        // 
     this->A::save(oa);   // 
     oa << this->b;    // INTERESTING 
    }        // PART OF THE 
    void load(I_Archive& ia)  // CLASS 
    {        // 
     this->A::load(ia);   // 
     ia >> this->b;    // 
    }        // 
}; 

// Consider classes 'C' and 'D' similar to 'B' 

void example_save(O_Archive& oa) 
{ 
    A* p1 = new B; 
    A* p2 = new C; 
    D* p3 = new D; 
    oa << Archive::declare_derived<A,B,C,D>(); 
    oa << p1 << p2; // Automatically detect the inheritance 
    oa << p3; // Store the instance as a usual pointer 
} 
void example_load(I_Archive& ia) 
{ 
    A* p1 = 0; 
    A* p2 = 0; 
    B* p3 = 0; 
    ia << Archive::declare_derived<A,B,C,D>(); 
    ia >> p1 >> p2; 
    ia >> p3; 
} 

問題は次のとおりです。次に、例として、私はこの種のコードを書くことができますか?それが派生タイプ、又は単に通常のポインタでインスタンスした場合、ポインタが、割り当てられた場合、このチェックの担当クラスI_Archiveで次load_pointer機能のようないくつかの機能と連動。

template <typename T> 
void I_Archive::load_pointer(T*& p) 
{ 
    delete p; 
    bool allocated; 
    this->load_bool(allocated); 
    if(allocated) 
    { 
     bool inheriance; 
     this->load_bool(inheriance); 
     if(inheriance) 
     { 
      unsigned long int i; 
      this->load_unsigned_long_int(i); 
      p = boost::static_pointer_cast< const Archive::allocator<T> >(this->alloc[&typeid(T)][i])->allocate(); 
     } 
     else 
      p = new T; // ERROR AT THIS LINE 
     *this >> *p; 
    } 
    else 
     p = 0; 
} 

私の問題:実は、私のコードは、行p = new T;上の次のエラーでコンパイルできません:

error: cannot allocate an object of abstract type ‘A’.

私が最初に驚いたが、私が持っている理由私は本当によく理解してこのエラー:機能load_pointerp1に呼び出されたときに、命令new TはタイプがABSがある場合、命令は実行されない場合であっても、禁止されているnew Aになりますトラクト。

私の質問:テンプレートを正しく使用してエラーを回避する方法が見つかりません。可能性のある回避策がありますか、コンパイラに言わせると"私は何をしているのか分かりません。抽象型をインスタンス化する必要はありません"

重要な注記:互換性の理由からC++ 11では動作しません。あなたが探している

+0

ケースの失敗でT 'は 'A'ある'入力表示されます。 –

+0

たぶん、あなたは単にあなたがA. –

+0

@ThomasBenardに固有のものを置くことが可能なAの特殊なケースのためにあなたの 'load_pointer'関数をオーバーロードすることができます:それは、アプリケーションのすべての抽象クラスを知るためにArchive''のresponsabilityではありません。つまり、新しい抽象クラスを追加するたびに 'Archive'クラスを編集しなければならないことを意味します。それは非常に悪いデザインです。 – Caduchon

答えて

2

トレイトはstd::is_abstractです。あなたが言及したように、あなたはC++ 11を使用することはできませんが、そのimplementationをboostから使用することができます。

あなたは、このと同様に、それを実装するために(再び、原因C++ 11を使用していないあなたの制約に、あなただけのhereから実装例を取ることができます)std::enable_ifと一緒is_abstractを使用することができます。

#include <iostream> 
#include <type_traits> 

struct A { 
    virtual void f() = 0; 
}; 

struct B : A { 
    void f() override {} 
}; 


template<typename T> 
std::enable_if_t<std::is_abstract<T>::value, T*> allocate() 
{ 
    return nullptr; 
} 

template<typename T> 
std::enable_if_t<!std::is_abstract<T>::value, T*> allocate() 
{ 
    return new T; 
} 

// Test 
template<typename T> 
T* test_alloc() 
{ 
    return allocate<T>(); 
} 

int main() 
{ 
    std::cout << test_alloc<A>() << "\n"; // Outputs nullptr 
    std::cout << test_alloc<B>() << "\n"; // Outputs an address 
} 

LIVE

関連する問題