【问题标题】:Using std string accessor with ostream operator <<将 std 字符串访问器与 ostream 运算符 << 一起使用
【发布时间】:2022-11-15 11:07:45
【问题描述】:

如果我创建一个类:

// First Example
#include <iostream>
#include <string>

class my_class {
  std::string str;
public:
  my_class(const char* s = "") : str(s) {}

  operator const char* () const { return str.data(); } // accessor
};

my_class mc1{"abc"};
std::cout << mc1; // Calls the char* accessor and successfully writes "abc" to screen output.

如果我这样修改类:

// Second Example
class my_class {
  std::string str;
public:
  my_class(const char* s = "") : str(s) {}

  operator std::string () const { return str; } // accessor
};

my_class mc1{"abc"};
std::string mystring = mc1; // Calls the string accessor
std::cout << mystring; // Also successfully writes "abc" to screen output.

但是,如果我尝试调用:

std::cout << mc1;

我会得到一个充满编译错误的页面,开头是:

错误 C2679:二进制“<<”:未找到采用“my_class”类型右手操作数的运算符(或没有可接受的转换)

我可以通过添加到第二个示例类来更正此错误:

  friend std::ostream& operator <<(std::ostream& os, my_class& rhs) {
    os << rhs.str;
    return os;
  }

我主要抄袭了针对这个问题的建议解决方案之一。但我不明白为什么有必要使用字符串访问器而不是 char* 访问器。

我期望成功编译并输出 mc1.str 的值,或者我会期望在第一个示例中尝试使用 char* 访问器函数时出现相同的错误。相反,我仅在第二个示例中收到了 C2679。

【问题讨论】:

  • 你最后一个SN-P的运营商应该是:friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const my_class&amp; rhs) { return os &lt;&lt; rhs.str; }。暴露的代码与您其余的 sn-ps 不匹配...
  • 该错误准确地描述了问题。流类没有从 my_class 到它理解的东西的转换;流类不知道如何处理my_class。换句话说,流类尚未针对 my_class 进行编程(很明显)。通过提供一个朋友实施,您明确提供所需的转换。这朋友函数被调用,因为它的参数与语句匹配
  • 谢谢@Scheff'sCat 发现了我的复制错误。

标签: c++ string overloading iostream accessor


【解决方案1】:

发生这种情况是因为函数的定义方式。对于 const char* 的情况,函数 cout 声明为

template< class CharT, class Traits >
basic_ostream<CharT, Traits>&
    operator<<( basic_ostream<CharT, Traits>& os, const char* s );

因此,当它分析std::cout &lt;&lt; mc1;时,它可以从cout推断出CharTTraits,并找到my_class::operator const char* ()mc1转换为const char*,因此重载解析成功,代码编译。

当您切换到使用 operator std::string () 并使用 std::cout &lt;&lt; mc1; 时,您现在需要为 operator &lt;&lt; 调用 std::string 重载,声明为

template< class CharT, class Traits, class Allocator >
std::basic_ostream<CharT, Traits>&
    operator<<( std::basic_ostream<CharT, Traits>& os,
                const std::basic_string<CharT, Traits, Allocator>& str );

在这个重载中,不仅第一个参数依赖于模板参数,第二个参数也是如此。这意味着编译器将尝试直接从mc1 推断出CharTTraitsAllocator 的类型。在此步骤中没有考虑转换运算符,因为 mc1 实际上不是 std::string 推导失败并且您没有可能的重载,因此代码无法编译。

【讨论】:

    猜你喜欢
    • 2017-04-13
    • 2011-01-15
    • 2018-03-31
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2018-04-22
    • 2023-01-09
    相关资源
    最近更新 更多