【问题标题】:Why cannot use cout with user-defined conversion to std::string?为什么不能将 cout 与用户定义的转换一起使用到 std::string?
【发布时间】:2017-08-17 02:49:08
【问题描述】:

这里我定义一个Date,并指定一个用户定义的转换。

class Date {
private:
    int day;
    int month;
    string dateStr;
public:
    Date(int _day, int _month) : day(_day), month(_month) {}

    operator const string() {
        ostringstream formattedDate;
        formattedDate << month << "/" << day;
        dateStr = formattedDate.str();
        return dateStr;
    }
};

转换为string时效果很好。

Date d(1, 1);
string s = d;

但是为什么不能直接和cout一起使用呢?

cout << d << endl; // The compiler complains that there is no suitable type marching << operator

但是,如果我使用char* 而不是string 进行用户定义的转换,我可以直接与cout 一起使用。为什么?

operator const char*() { 
    ostringstream formattedDate;
    formattedDate << month << " / " << day;
    dateStr = formattedDate.str();
    return dateStr.c_str();
}

ps。我知道直接重载&lt;&lt; 可以很好地输出。但我的问题是:为什么不能将&lt;&lt; 与用户定义的转换一起使用到std::string

【问题讨论】:

  • 什么“错误”你得到了?构建错误?崩溃?出乎意料的输出?如果可能,请复制粘贴(作为文本)。
  • 另外,如果你想输出你的对象,我宁愿建议你重载全局operator&lt;&lt;函数,而不是依赖转换运算符。 (如果你还想拥有一个转换运算符,你可以使用重载的&lt;&lt; 运算符来创建它。)

标签: c++ type-conversion operator-overloading implicit-conversion cout


【解决方案1】:

注意std::string是模板std::basic_string的实例化,the signature of operator&lt;&lt; for 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);

那么对于cout &lt;&lt; d;,必须推导出std::basic_string的模板参数;但是type deduction does not consider implicit conversions;

类型推导不考虑隐式转换(除了上面列出的类型调整):这是重载解析的工作,稍后会发生。

这意味着扣除将失败;那么没有候选函数是可行的。

但是operator&lt;&lt; for const char*没有这样的问题;隐式转换生效,然后就可以正常工作了。

为了解决这个问题,您可以使用显式转换来避免模板参数推导;或直接在类型Date 上重载operator&lt;&lt;

【讨论】:

  • 好答案,也许补充一点,显式转换仍然应该得到想要的结果cout &lt;&lt; (std::string)d &lt;&lt; endl;我认为
  • @xander 请不要建议在 C++ 中使用 C 风格的强制转换。它们是进行类型转换的所有可能方法中最危险的
  • @Angew 但这不是经典转换,它是调用operator string() 的显式类型转换。我不知道如何用 C++ cast 风格调用它,你可以使用 static_cast&lt;std::string&gt;(d) 或者什么是正确的方法?
  • @xander 是的,你可以使用static_cast,或者你也可以使用std::string{d}(Type)expr 始终是 C 风格的强制转换,可以执行以下任何操作:static、static+const、reinterpret、reinterpret+const;取决于Typeexpr。这就是为什么使用它是个坏主意:你真的不知道会发生什么。
猜你喜欢
  • 1970-01-01
  • 2018-02-25
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多