std::string 类继承和繁琐的 C++ 重载解析

2024-01-01

我需要延长std::basic_string处理路径字符串和不同的operator+:

#include <string>

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;

    path_basic_string(const base_type & r) :
        base_type(r)
    {
    }

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

using path_string = path_basic_string<char, std::char_traits<char>, std::allocator<char> >;

template <class t_elem, class t_traits, class t_alloc>
inline path_basic_string<t_elem, t_traits, t_alloc> &&
    operator +(
        path_basic_string<t_elem, t_traits, t_alloc> && l,
        std::basic_string<t_elem, t_traits, t_alloc> && r)
{
    std::basic_string<t_elem, t_traits, t_alloc> && l_str = std::move(l);
    std::basic_string<t_elem, t_traits, t_alloc> && r_str = std::move(r);

    const bool has_right = !r_str.empty();
    return std::move(
        path_basic_string<t_elem, t_traits, t_alloc>{
            std::move(std::move(l_str) + (has_right ? "/" : "") + (has_right ? std::move(r_str) : std::move(std::basic_string<t_elem, t_traits, t_alloc>{})))
        });
}

template <class t_elem, class t_traits, class t_alloc>
inline path_basic_string<t_elem, t_traits, t_alloc>
    operator +(
        const path_basic_string<t_elem, t_traits, t_alloc> & l,
        const std::basic_string<t_elem, t_traits, t_alloc> & r)
{
    const std::basic_string<t_elem, t_traits, t_alloc> & l_str = l;

    const bool has_right = !r.empty();
    return path_basic_string<t_elem, t_traits, t_alloc>{
        l_str + (has_right ? "/" : "") + (has_right ? r : std::basic_string<t_elem, t_traits, t_alloc>{})
    };
}

int main()
{
    path_string a;
    std::string b;
    std::string c;
    const path_string test = a + (b + c);

    return 0;
}

At the https://godbolt.org/z/jhcWoh https://godbolt.org/z/jhcWoh我有这些错误:

x86 MSVC 19 2015 U3:

/opt/compiler-explorer/windows/19.00.24210/include/xlocale(341):
warning C4530: C++ exception handler used, but unwind semantics are
not enabled. Specify /EHsc

<source>(61): error C2666: 'operator +': 3 overloads have similar
conversions

<source>(44): note: could be
'path_basic_string<char,std::char_traits<char>,std::allocator<char>>
operator +<char,std::char_traits<char>,std::allocator<char>>(const
path_basic_string<char,std::char_traits<char>,std::allocator<char>>
&,const
std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&)'

<source>(28): note: or      
'path_basic_string<char,std::char_traits<char>,std::allocator<char>>
&&operator
+<char,std::char_traits<char>,std::allocator<char>>(path_basic_string<char,std::char_traits<char>,std::allocator<char>> &&,std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&&)'

/opt/compiler-explorer/windows/19.00.24210/include/xstring(2310):
note: or      
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>
std::operator
+<char,std::char_traits<char>,std::allocator<char>>(const std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&,const
std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&)'

/opt/compiler-explorer/windows/19.00.24210/include/xstring(2380):
note: or      
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>
std::operator
+<char,std::char_traits<char>,std::allocator<char>>(const std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&,std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&&)'

/opt/compiler-explorer/windows/19.00.24210/include/xstring(2390):
note: or      
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>
std::operator
+<char,std::char_traits<char>,std::allocator<char>>(std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&,const
std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&)'

/opt/compiler-explorer/windows/19.00.24210/include/xstring(2400):
note: or      
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>
std::operator
+<char,std::char_traits<char>,std::allocator<char>>(std::basic_string<char,std::char_traits<char>,std::allocator<char>> &&,std::basic_string<char,std::char_traits<char>,std::allocator<char>>
&&)'

<source>(61): note: while trying to match the argument list
'(path_string,
std::basic_string<char,std::char_traits<char>,std::allocator<char>>)'

<source>(61): note: note: qualification adjustment (const/volatile)
may be causing the ambiguity

Compiler returned: 2

x86-64 海湾合作委员会 5.4 (with --std=c++11):

source>: In function 'int main()':

<source>:61:40: warning: ISO C++ says that these are ambiguous, even
though the worst conversion for the first is better than the worst
conversion for the second:

     const path_string test = a + (b + c);

                                        ^

<source>:44:5: note: candidate 1: path_basic_string<t_elem, t_traits,
t_alloc> operator+(const path_basic_string<t_elem, t_traits,
t_alloc>&, const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&)
[with t_elem = char; t_traits = std::char_traits<char>; t_alloc =
std::allocator<char>]

     operator +(

     ^

In file included from
/opt/compiler-explorer/gcc-5.4.0/include/c++/5.4.0/string:52:0,

                 from <source>:1:

/opt/compiler-explorer/gcc-5.4.0/include/c++/5.4.0/bits/basic_string.h:4854:5:
note: candidate 2: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>
std::operator+(const std::__cxx11::basic_string<_CharT, _Traits,
_Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]

     operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,

     ^

Compiler returned: 0

我至少知道一种解决方法。

但到底发生了什么? 可笑的是,我还必须再次超载以避免超载碰撞混乱?

Update: 通过删除修复const and single reference来自所有basic_string所有人的善意论点operator+。似乎可以解决这个问题。


首先,使用 move-from-value 而不是const& and &&过载。

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

并摆脱base_type const& ctor.

其次,使该 ctor 明确:

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

因为路径与字符串不同。

第三,清理你的template operator+并使其成为 ADL“Koenig”运算符,按值获取其左侧。哦,不要通过右值引用返回任何内容,这是有毒的。

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;
}

并消除所有噪音。

接下来,继承ctorsbase_type.

最后,使用以下方法实现附加+=并使操作对称:

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+这里很奇特,因为它只能通过 ADL 找到,但它实际上在base类的类型。

这意味着至少一个参数必须是该类型的实例(或者具有该类型的实例作为模板参数)才能找到它。

然后如果需要的话会发生转换为基数。

我按值取 LHS,因为移动字符串是便宜到免费的,而且我们需要一个字符串用于输出。通过按值获取 LHS 并使用其缓冲区(移动后)作为返回值,我们得到了高效的链式加法:

a+b+c+d+e

becomes

(a+b)+c+d+e

现在的返回值a+b(纯右值)然后用作 lhs 参数(a+b)+c.

缓冲区的回收继续进行;仅创建一个缓冲区(从第一个+),然后移动它、调整大小(希望有效)并重新用于表达式的其余部分。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

std::string 类继承和繁琐的 C++ 重载解析 的相关文章

随机推荐

  • 如何获取RSpec当前的上下文名称?

    如果我有这样的 rspec describe Foo do init go here describe Sub Foo do it should Bar do test go here puts lt need Foo Sub Foo sh
  • 从工具栏提交 SAS 代码或宏

    是否可以将 SAS 脚本或宏分配给 Base SAS 中的工具栏按钮 即 您可以 dm 宏或 sas 脚本吗 当然 这是一种方法 转到工具 gt 自定义 选择自定义选项卡 单击 添加工具 最左边的按钮 命令 一词的正上方 创建一个新的空白按
  • ASP.NET - 条件 Web.config

    我是 ASP 新手 想知道它是否有条件 编译 我知道它没有编译 我的意思是 我的应用程序交付给不同的用户 每个都有自己的条件应用程序编译 现在我需要有条件地更改 Web config 有没有办法使用条件编译符号 EOG 如果 Daniel
  • 在 C++ 中传递具有多个条目的结构

    我试图传递一个坐标 它被定义为具有 2 个整数参数的结构 该结构称为 coord 如下所示 UpdateB 0 0 其中输入参数的类型为 coord 即在上面的语句中我试图传递一个坐标0 0 UpdateB是某种功能 我收到错误 有什么想法
  • 在 Rcpp 中按列对数据框排序

    有没有简单的方法可以通过 RCpp 中的两列 或多列或一列 对 DataFrame 进行排序 网上有很多排序算法 或者我可以使用std sort带有 DataFrame 的包装器 但我想知道 RCpp 或 RCppArmadillo 中是否
  • jQuery click() 没有点击?

    我以为 jQuery 的click 可以让我们添加一个处理程序或仅单击一个元素吗 但是 我尝试过 function setTimeout function a first trigger click or click the same 30
  • 分配空列表

    我真的不知道我是如何偶然发现这个的 我也不知道该怎么想 但显然 是 python 中的合法操作 所以也是 but 不允许 虽然似乎没有任何效果 但我想知道 到底是什么 这和Python的多重赋值 序列拆包 有关 a b c 1 2 3 工作
  • 'FBSession:未提供 AppID

    我刚刚使用新的 iOS 版 Facebook 3 0 SDK 更新了我的应用程序 在此之前 我使用的是利用 FBSessionDelegate 和 FBRequestDelegate 的 SDK 在该 SDK 中 我们必须将此代码放置在 a
  • 应用程序不会从命令行完整路径启动,但会在 CD 到目录后启动

    我正在尝试从注册表运行 Net C 应用程序Run键 在HKEY LOCAL MACHINE SOFTWARE Microsoft Windows CurrentVersion Run 其他字符串值存在并启动一切都很好 但由于某种莫名其妙的
  • 我将华氏温度转换为摄氏度的代码有什么问题?

    Programme to covert Farenheight to Celcius F input Enter Value F F 32 9 5 print The temperature is F Degrees Celcius 当我尝
  • 在 Swift 中使用 NSDate 进行 NSSortDescriptor 排序

    我如何使用托管对象的日期属性对 NSFetchRequest 进行排序 这样它就创建了一个按日期顺序排列的数组 到目前为止 这是我的代码 var request NSFetchRequest NSFetchRequest entityNam
  • 尝试返回父记录的子记录的所有列

    我正在寻找一种解决方案 通过该解决方案可以获得父记录的所有子记录 我找到了一个满足我的需求的解决方案 如下所示 https stackoverflow com a 28366310 726802 唯一的问题是上述解决方案是连接 ID 当前结
  • Google Now 类似于 iOS 上的界面

    所以 我非常喜欢 Android 上的 Google Now 卡片界面 最近它甚至登陆了 iOS 有没有任何教程或示例项目可以帮助我为我的 iOS 应用程序创建卡片界面 根据我的研究 我已经能够使用自定义 UICollectionViewF
  • Twitter Bootstrap:中心药丸

    我的问题是如何使药片居中 我尝试在周围添加中心块并更改float left to float center但没有任何帮助 这已经变得简单多了 你只需要使用text center容器上的类 并应用display inline block to
  • 致命异常:主要 - 我的应用程序不再在 Android 设备上运行,但可以在桌面上运行

    这是我第一次遇到这个问题 我完全不知道该怎么办 我曾经在虚拟设备以及手机和平板电脑上测试我的应用程序 我经常测试它 比如每 1 2 小时一次 有一次 它停止在所有 Android 设备上运行 但它仍然可以在桌面上运行 在 Android 设
  • 如何解决Chrome使用xhr轮询时的6个连接限制

    我最近发现Chrome似乎有6个连接限制 Chrome 在传输一定量的数据后挂起 等待可用的套接字 https stackoverflow com questions 23679968 chrome hangs after certain
  • jquery 选择除 div 及其子元素之外的所有元素

    我有这个 html css 代码 div div div div div div div div div div
  • 在调试过程中,单步执行程序时有时会出现“变量不可用”(Android Studio 3.5+)

    通常 变量在 Android Studio 版本 3 5 2 的调试模式下显示 但有时 当我单步执行程序时 我突然得到 变量不可用 见下图 这次我在存在错误的代码中得到了这个 所以我真的很想知道那里发生了什么 它是在调试模式下运行测试期间发
  • 使用 C++ 的简单 HTTP 请求

    在您将此标记为冗余之前 请注意我已经尝试了网上发布的许多方法 包括堆栈溢出 但它们都无法满足我的需求 另请注意 我对编程世界还很陌生 所以请原谅我滥用技术术语 现在我正在编写一个 C 程序 它计算来自用户计算机的一些数据 例如 IP 地址
  • std::string 类继承和繁琐的 C++ 重载解析

    我需要延长std basic string处理路径字符串和不同的operator include