提问人:ollydbg23 提问时间:2/24/2023 最后编辑:ollydbg23 更新时间:2/28/2023 访问量:122
为 std::span<T 添加成员函数 substr>它模仿 string_view::substr
adding member function substr for std::span<T> which imitates the string_view::substr
问:
在我的代码中,我想创建一个通过扩展类来命名的新类,但是新类具有一些额外的成员函数,这些函数在 中不存在。Span
std::span
Span
std::span
一种是将函数添加到 ,该函数已实现且工作正常。有关详细信息,请参阅我之前的问题:从 std::span 中删除第一个元素的方法是什么?remove_prefix
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;
}
上面的代码在支持 C++ 的 g++ 下构建并运行正常。我的问题是:我的实现正确吗?因为我在代码中使用了这么多。其实已经有了一个函数名,我做的就是做一个函数名别名。static_cast
std::span
subspan
substr
有什么想法吗?谢谢。
答:
所以,我认为你应该考虑改变你的设计,而不是改变STL。
首先,从 派生是不安全的,因为它没有虚拟析构函数,所以有可能泄漏内存:是否可以从 STL 容器继承实现,而不是委托?std::span
其次,它们根本不是虚拟的,这意味着继承被错误地使用,因为在我看来,它的目的是创建要覆盖的接口,以便模块的细节可以相互隐藏。
很难说如果不了解您的设计,我会怎么做,但我建议一些解决方案:
- 使用多态性或显式模板专用化 (with ) 来定义这两个类的方法。
constexpr if
- 为您的具体设计创建一个界面(解决您的最终目标),隐藏包含此视图之一的细节。
- 您可以从其中之一构造并仅使用其中之一。
std::span<const char>
std::string_view
评论
std::span<T>
不是一个容器,所以它不太可能是任何人的容器。您甚至可以通过私下继承并公开所有成员来确保没有人指向delete
std::span<T> *
Span<T>
std::string_view
std::span<T>
std::span
Span
std::span
你的实现没有错,但可以简化为remove_prefix
constexpr void remove_prefix(std::size_t n) {
*this = subspan(n);
}
你的实现是错误的,因为你static_casting对一个对象的左值引用,该对象的最派生类型是 ,而不是 。您可以修复它:substr
std::span<T>
Span<T>
constexpr Span substr(std::size_t pos, std::size_t count){
return subspan(pos, count);
}
但是,我不会这样做。相反,我会更改调用代码以使用您重载的免费函数和(等)。std::span<T>
std::string_view
template<typename T>
constexpr void remove_prefix(std::span<T> & span, std::size_t n) {
span = span.subspan(n);
}
template<typename CharT, typename Traits>
constexpr void remove_prefix(std::basic_string_view<CharT, Traits> & view, std::size_t n) {
view.remove_prefix(n);
}
template<typename T>
constexpr std::span<T> substr(std::span<T> span, std::size_t n) {
return span.subspan(n);
}
template<typename CharT, typename Traits>
constexpr std::basic_string_view<CharT, Traits> substr(std::basic_string_view<CharT, Traits> view, std::size_t n) {
return view.substr(n);
}
评论
substr
std::size_t pos, std::size_t count
评论