向标准模板的特化添加新方法(std::vector,std::list...)

Adding new methods to specializations of standard templates (std::vector, std::list...)

我想为 std::list<Picture> 创建专门化,这将为包含 Picture 的列表添加额外的方法,但我不知道是否可以通过我尝试过的这种方式实现。

我试过了:

template <typename _Alloc = std::allocator<Picture>> 
   class list : protected _List_base<Picture, _Alloc>
{
public:
  void draw()
  {
    // some code
  }
};

int main()
{
  std::list<Picture> myList;
  //adding elements to mylist
  mylist.draw();
  return 0;
}

编译后报错:

error: ‘class std::__cxx11::list<Picture>’ has no member named ‘draw’

标准明确允许 STL 类型的特化。但是,您需要专注于命名空间 std.

另外,继承自_List_base是C++标准所禁止的。如 https://en.cppreference.com/w/cpp/language/identifiers 中所列,在您的程序中使用保留标识符会使您的程序格式错误,并且所有以下划线后跟大写字母开头的标识符都是保留的。

专攻 STL 类型

您可以专门化 STL 类型,但正如在另一个答案中提到的,它们需要在命名空间 std 中专门化。这意味着您应该这样做:

namespace std {
    template <typename _Alloc = std::allocator<Picture>> 
    class list<Picture, _Alloc> { 
        /* stuff */ 
    };
}

或者这个:

template<typename _Alloc = std::allocator<Picture>>
class std::list<Picture, _Alloc> {
    /* stuff
};

也就是说,不要继承自 _List_base。 class 是 std::list 的一个实现细节,这意味着它是标准库的一个特定实现选择实现 std::list 的一种方式。其他编译器可能没有。

解决您的问题

如果你想要一个有 .draw() 函数的类列表 class,你可以继承 std::list:

template<class Drawable>
class DrawableList : public std::list<Drawable>
{
   public: 
    // It's handy to have this to refer to the base
    using base_t = std::list<Drawable>; 
    
    using base_t::base_t; // Use std::list`s constructor
    
    // Add your draw function
    void draw(int x, int y) {
        for(Drawable& item : *this) {
            item.draw(x, y); 
        }
    }
};

std::list

继承的注意事项

std::list 继承有一些注意事项。因为 std::list 不需要动态多态性,这意味着它没有虚拟析构函数(或任何其他虚拟方法)。你基本上只是在 std::list.

周围做一个包装器 class

此外,如果您向 DrawableList 添加任何字段,则在将其复制到 std::list 时这些字段可能会被截断。这称为对象切片。

DrawableList<Picture> a = /* stuff */;

std::list<Picture> b = a; // This will compile without any issues

DrawableList<Picture> c = b; // Oops; any extra fields you had in a got cut off

或者,只需使用一个免费的 draw 函数:

void draw(std::list<Picture>& pictures, int x, int y) {
    for(auto& picture : pictures) {
        picture.draw(x, y); 
    }
}