向标准模板的特化添加新方法(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);
}
}
我想为 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
.
此外,如果您向 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);
}
}