在我的代码中,我想通过扩展std::span
类来创建一个名为Span
的新类,但是新的Span
有一些额外的成员函数,而std::span
中不存在这些函数。
一种是在std::span
中添加remove_prefix
函数,该函数已经实现,工作正常,详见我前面的问题:what is the way to remove the first element from a std::span?
现在我想添加另一个名为substr
的成员函数(我试着模仿std::string_view
的一些成员函数,因为我需要在我的设计中同时支持std::span<T>
和std::string_view
)。在旧代码中,我只有std::string_view
支持,所以它有一些代码片段像sv.substr()
,现在我希望sv
可以是通用的,这意味着它可能是std::string_view
或std::span<T>
(Span<T>
)。
下面是我用来解决这个问题的最小示例代码:
#include <iostream>
#include <span>
using namespace std;
// Span class which is derived class from std::span
// add remove_prefix and substr function which is similar like std::string_view
template<typename T>
class Span : public std::span<T>
{
public:
// Inheriting constructors from std::span
using std::span<T>::span;
// add a public function which is similar to std::string_view::remove_prefix
constexpr void remove_prefix(std::size_t n) {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
// add another public function substr, which is the span::subspan
constexpr Span substr(std::size_t pos, std::size_t count){
auto& self = static_cast<std::span<T>&>(*this);
auto ret = self.subspan(pos, count);
return static_cast<Span<T>&>(ret);
}
};
float arr[3] = {1.0, 2.0, 3.0};
int main()
{
Span<float> a(arr, 2);
Span<float> b = a.substr(0, 1);
return 0;
}
上面的代码在g 下构建并运行正常,并支持C20。我的问题是:我的实现是否正确?因为我在代码中使用了太多的static_cast
。事实上,std::span
已经有一个名为subspan
的函数,我所做的只是使函数名别名为substr
。
有什么主意吗?谢谢。
2条答案
按热度按时间cqoc49vn1#
您的
remove_prefix
实现没有错,但是可以简化为substr
的实现是错误的,因为您正在静态转换一个左值引用到一个对象,该对象的最大派生类型是std::span<T>
,而不是Span<T>
。但是,我不会这样做,而是将调用代码改为使用为
std::span<T>
和std::string_view
(et. al.)重载的自由函数。4dbbbstv2#
谢谢你的提问!
所以,我认为你应该考虑改变你的设计,而不是改变STL(:
首先,从
std::span
派生是不安全的,因为它没有虚析构函数,所以有可能泄漏内存:Is it okay to inherit implementation from STL containers, rather than delegate?其次,它们根本不是虚拟的,这意味着继承被错误地使用了,因为,在我看来,它的目的是创建要重写的接口,以便模块的细节可以相互隐藏。
很难说如果不了解您的设计,我会怎么做,但我建议您使用以下解决方案:
constexpr if
)为两个类定义方法;std::string_view
构造std::span<const char>
,并且只使用其中一个。