【问题标题】:Avoid allocation of abstract type with templates避免使用模板分配抽象类型
【发布时间】:2016-03-30 11:39:47
【问题描述】:

背景:我编写了一些用于归档数据的工具,类似于 boost 中的归档方式。然后,例如,我可以编写这种代码:

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; 行出现以下错误:

错误:无法分配抽象类型“A”的对象。

我一开始很惊讶,但是我真的很明白为什么会出现这个错误:当函数 load_pointerp1 上调用时,指令 new T 变为 new A 这是禁止,即使在类型是抽象的情况下指令永远不会运行。

我的问题:我找不到正确使用模板的方法来避免我的错误。是否有可能的解决方法来做到这一点或对编译器说“我知道我在做什么,你永远不必实例化抽象类型”

重要提示:出于兼容性原因,我无法使用 C++11。

【问题讨论】:

  • 在失败的情况下,类型TA
  • 也许您可以简单地为 A 的特殊情况重载 load_pointer 函数,您可以在其中放置特定于 A 的内容。
  • 我的问题是,既然您可以使用分配器动态构建派生类型,为什么不能使用相同的方式来构建非派生类型?
  • @Caduchon 使用trivial 实现enable_if 和一些重载可以像this 一样完成。你当然需要typename std::enable_if&lt;...&gt;::type
  • this 稍微干净一些。

标签: c++ templates abstract-class allocation c++98


【解决方案1】:

您正在寻找的特征是std::is_abstract。正如您所提到的,您不能使用 C++11,但您可以使用来自 boost 的 implementation

然后您可以将is_abstractstd::enable_if 一起使用(同样,由于您不使用C++11 的限制,您可以只使用here 中的示例实现)来实现它,类似于:

#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

【讨论】:

    猜你喜欢
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    • 2019-03-30
    • 1970-01-01
    • 2019-02-27
    相关资源
    最近更新 更多