在C ++模板

时间:2015-07-28 10:37:06

标签: c++ templates

在C ++中实现侵入式容器时,我遇到了一些奇怪的问题。 鉴于以下简化代码:

struct IFace {
  virtual int foo() const = 0;
};

struct Impl : public IFace {
  int foo() const { return 111; }
};

template <typename T> struct IntrusiveHook {
  T item;
  IntrusiveHook<T>* next;
};

template <typename T> struct IntrusiveList {
  IntrusiveList() : head(0), tail(0) {}

  template <typename U>
  void add(IntrusiveHook<U>& addItem) {
    if (0 == head) {
      head = reinterpret_cast<IntrusiveHook<T>*>(&addItem);
      tail = head;
    }
    else {
      tail->next = reinterpret_cast<IntrusiveHook<T>*>(&addItem);
      tail = tail->next;
    }
  }
  IntrusiveHook<T>* head;
  IntrusiveHook<T>* tail;
};

void testList() {
  IntrusiveHook<Impl> impl;
  IntrusiveList<IFace> list;

  list.add(impl);
  // list.head->item.foo();
}

我收到以下错误消息 - 对于“添加” - 调用(当如上所述注释掉行list.head->item.foo()时):

error C2259: 'IFace' : cannot instantiate abstract class
due to following members:
'int IFace::foo(void) const' : is abstract
testwas.cpp(7) : see declaration of 'IFace::foo'
testwas.cpp(25) : see reference to class template instantiation 'IntrusiveHook<T>' being compiled
with
[
  T=IFace
]
testwas.cpp(41) : see reference to function template instantiation 'void IntrusiveList<T>::add<Impl>(IntrusiveHook<Impl> &)' being compiled
with
[
  T=IFace
]

在第list.head->item.foo()行注释时,我得到一个不同的编译错误,前一个被遗漏了(这是一个奇怪的行为,并且在VC ++和gcc编译器上都会发生)

有问题的调用似乎是tail->next = ...,或者特别是此处使用的抽象类型上的运算符->

所以: 如何解决这个问题?

  • foo中添加IFace的默认实施 - 这不是我想要的,但它解决了问题
  • 一种hacky解决方案:将tail->next重写为

    reinterpret_cast<IntrusiveHook<U>*>(tail)->next = &addItem;

    tail = reinterpret_cast<IntrusiveHook<T>*>(reinterpret_cast<IntrusiveHook<U>*>(tail)->next); - 但它似乎不适用于VC ++(2010),但使用gcc

  • ......或表演其他一些丑陋的演员

为什么首先是一个问题?通常,使用运算符“ - &gt;”访问指针类型应该不是问题。

任何帮助将不胜感激。谢谢!

编辑:

为方便起见,我希望IntrusiveHook已经将项目作为实例包含在内。这也是侵入性的伎俩 - 当我做对了 - 只需将指针功能添加到项目而不更改项目本身。 “new”不是一个选项,因为代码应该在没有new的嵌入式环境中运行。

当然我也想使用带有抽象项的列表,因为using类不会知道实现类。

1 个答案:

答案 0 :(得分:2)

据我所知,问题是在IntrusiveHook<T>*中投射到IntrusiveList::add。您正在将addItem投射到IntrusiveHook<IFace>IntrusiveHook<IFace>的成员item的成员为IFace。但是IFace是抽象的,所以你不能用该类型声明变量 - 你必须使用指针或引用。

所以你必须

  • IntrusiveHook::itemT类型更改为T*
  • 添加构造函数IntrusiveHook(T* item) : item(item) {}
  • impltestList()的声明更改为IntrusiveHook<Impl> impl(new Impl)
  • 最后将list.head->item.foo()更改为list.head->item->foo()

(见this code on cpp.sh。)

如果您不想更改IntrusiveList<IFace*>,也可以使用IntrusiveList<Impl>IntrusiveList<IFace>代替IntrusiveHook