添加用于 `std::span` 的成员函数 `substr`,模仿 `string_view::substr` 的行为。

huangapple go评论67阅读模式
英文:

adding member function substr for std::span<T> which imitates the string_view::substr

问题

在我的代码中,我想要创建一个名为Span的新类,通过扩展std::span类来实现,但新的Span类具有一些额外的成员函数,这些函数在std::span中不存在。

其中一个是将remove_prefix函数添加到std::span中,该函数已经实现并正常工作。有关详细信息,请参阅我的先前的问题:如何从std::span<T>中删除第一个元素?

现在,我想要添加另一个名为substr的成员函数(我试图模仿std::string_view的一些成员函数,因为我需要在我的设计中支持std::span&lt;T&gt;std::string_view两者)。在旧代码中,我只支持std::string_view,因此有一些代码片段类似于sv.substr(),现在我希望sv可以更通用,这意味着它可以是std::string_viewstd::span&lt;T&gt;Span&lt;T&gt;)。

以下是我用来解决这个问题的最小示例代码:

#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++20支持的g++下可以构建和运行。我的问题是:我的实现是否正确?因为我在代码中使用了许多static_cast。实际上,std::span已经有一个名为subspan的函数,我所做的只是创建了一个函数名称别名substr

有任何想法吗?谢谢。

英文:

In my code, I would like to create a new class named Span by extending the std::span class, but the new Span has some extra member functions which does not exist in std::span.

One is adding the remove_prefix function to std::span, which is implemented and works OK. See my previous question for details: what is the way to remove the first element from a std::span<T>?

Now I would like to add another member function named substr(I try to imitates some member functions of std::string_view because I need to support both std::span&lt;T&gt; and std::string_view in my design). In the old code, I have only std::string_view support, so it has some code snippet like sv.substr(), now I would like sv could be general, which means it could be either std::string_view or std::span&lt;T&gt;(Span&lt;T&gt;).

Here is the minimal sample code I used to solve this issue:

#include &lt;iostream&gt;
#include &lt;span&gt;

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&lt;typename T&gt;
class Span : public std::span&lt;T&gt;
{
public:
    // Inheriting constructors from std::span
    using std::span&lt;T&gt;::span;

    // add a public function which is similar to std::string_view::remove_prefix
    constexpr void remove_prefix(std::size_t n) {
        auto&amp; self = static_cast&lt;std::span&lt;T&gt;&amp;&gt;(*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&amp; self = static_cast&lt;std::span&lt;T&gt;&amp;&gt;(*this);
        auto ret = self.subspan(pos, count);
        return static_cast&lt;Span&lt;T&gt;&amp;&gt;(ret);
    }
};

float arr[3] = {1.0, 2.0, 3.0};

int main()
{
    Span&lt;float&gt; a(arr, 2);
    Span&lt;float&gt; b = a.substr(0, 1);
    return 0;
}

The above code builds and runs OK under g++ with C++20 support. My question is: is my implementation correct? Because I use so many static_cast in the code. In-fact, std::span already has a function named subspan, what I do is just make a function name alias substr.

Any ideas? Thanks.

答案1

得分: 2

你的 remove_prefix 实现没有问题,但可以简化为:

constexpr void remove_prefix(std::size_t n) {
    *this = subspan(n);
}

你的 substr 实现有问题,因为你将一个 lvalue 引用强制转换为一个其最终派生类型为 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);
}
英文:

Your implementation of remove_prefix isn't faulty, but it can be simplified to

constexpr void remove_prefix(std::size_t n) {
    *this = subspan(n);
}

Your implementation of substr is faulty, because you are static_casting an lvalue reference to an object who's most derived type is std::span&lt;T&gt;, not Span&lt;T&gt;. You can fix it:

constexpr Span substr(std::size_t pos, std::size_t count){
    return subspan(pos, count);
}

However, I wouldn't do this. I would instead change the calling code to use free functions that you've overloaded for std::span&lt;T&gt; and std::string_view (et. al.)

template&lt;typename T&gt;
constexpr void remove_prefix(std::span&lt;T&gt; &amp; span, std::size_t n) {
    span = span.subspan(n);
}

template&lt;typename CharT, typename Traits&gt;
constexpr void remove_prefix(std::basic_string_view&lt;CharT, Traits&gt; &amp; view, std::size_t n) {
    view.remove_prefix(n);
}

template&lt;typename T&gt;
constexpr std::span&lt;T&gt; substr(std::span&lt;T&gt; span, std::size_t n) {
    return span.subspan(n);
}

template&lt;typename CharT, typename Traits&gt;
constexpr std::basic_string_view&lt;CharT, Traits&gt; substr(std::basic_string_view&lt;CharT, Traits&gt; view, std::size_t n) {
    return view.substr(n);
}

答案2

得分: 1

So, I think you should consider changing your design rather than changing STL.

First, it is unsafe to derive from std::span, because it does not have a virtual destructor, so there is a chance to leak memory: https://stackoverflow.com/questions/2034916/is-it-okay-to-inherit-implementation-from-stl-containers-rather-than-delegate

Secondly, they are not virtual at all, meaning that inheritance is used incorrectly because, as it seems to me, its purpose is to create interfaces to override, so that details of modules can be hidden from each other.

It's hard to say what I would do without knowing your design, but there are some solutions I'd suggest:

  • Use polymorphism or explicit template specialization (with constexpr if) to define methods for both classes.
  • Create an interface for your concrete design (solving your final goal) hiding the details of containing one of these views.
  • You can construct std::span<const char> from std::string_view and use just one of them.
英文:

So, I think you should consider changing your design rather than changing STL.

First, it is unsafe to derive from std::span, because it does not have a virtual destructor, so there is a chance to leak a memory: https://stackoverflow.com/questions/2034916/is-it-okay-to-inherit-implementation-from-stl-containers-rather-than-delegate

Secondly, they are not virtual at all meaning that inheritance is used incorrectly, because, as it seems to me, its purpose is to create interfaces to override, so that details of modules can be hidden from each other.

It's hard to say what would I do without knowing your design, but there are some solutions I'd suggest:

  • Use polymorphism or explicit template specialization (with constexpr if) to define methods for both classes.
  • Create an interface for your concrete desing (solving your final goal) hiding the detail of containing one of this views.
  • You can construct std::span&lt;const char&gt; from std::string_view and use just one of them.

huangapple
  • 本文由 发表于 2023年2月24日 10:47:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75552191.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定