std::string class inheritance and tedious c++ overload resolution

蓝咒 提交于 2019-12-05 05:31:09

First things first, use move-from-value instead of const& and && overloads.

path_basic_string(base_type r) :
    base_type(std::move(r))
{
}

and get rid of base_type const& ctor.

Second, make that ctor explicit:

explicit path_basic_string(base_type r) :
    base_type(std::move(r))
{
}

as a path is a different thing than a string.

Third, clean up your template operator+ and make it an ADL "Koenig" operator that takes its left hand side by value. Oh, and don't return anything by rvalue reference, that is toxic.

friend path_basic_string
    operator +(
        path_basic_string l,
        base_type const& r)
{
  base_type& l_str = l;
  if (!r.empty())
    l = path_basic_string( std::move(l_str) + "/" + r );
  return l;
}

and get rid of all that noise.

Next, inherit ctors from base_type.

Finally, implement appending using += and make the operations symmetric:

template <class t_elem, class t_traits, class t_alloc>
class path_basic_string : public std::basic_string<t_elem, t_traits, t_alloc>
{
public:
    using base_type = std::basic_string<t_elem, t_traits, t_alloc>;

    path_basic_string() = default;
    path_basic_string(const path_basic_string & ) = default;
    path_basic_string & operator =(const path_basic_string &) = default;

    using base_type::base_type;

    explicit path_basic_string(base_type r) :
        base_type(std::move(r))
    {
    }
    path_basic_string& operator+= ( base_type const& rhs ) & {
      if (!rhs.empty())
      {
        base_type& self = *this;
        self += '/';
        self += rhs;
      }
      return *this;
    }
    friend path_basic_string operator+(
            base_type l,
            base_type const& r
    )
    {
      path_basic_string l_path(std::move(l));
      l+=r;
      return l;
    }
};

operator+ here is fancy as it is only findable via ADL, yet it actually operates on the base type of the class.

This means that at least one of the arguments must be an instance of this type (or have an instance of this type as a template argument) in order for it to be found.

Then conversion-to-base occurs if required.

I take LHS by value, because moving a string is cheap-to-free, and we need a string for output. By taking LHS by value and using its buffer (after moving it) for the return value, we get efficient chained addition:

a+b+c+d+e

becomes

(a+b)+c+d+e

now the return value of a+b (a prvalue) is then used as the lhs argument of (a+b)+c.

This recycling of the buffer continues; only one buffer is created (from the first +), and it is then moved, resized (hopefully efficiently) and reused for the rest of the expression.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!