【问题标题】:Implicit conversion to std::string [duplicate]隐式转换为 std::string [重复]
【发布时间】:2012-12-02 17:07:30
【问题描述】:

可能重复:
Overload resolution failure when streaming object via implicit conversion to string

我知道这样做不是一个好主意,但我真的很想知道下面的代码无法编译的原因(即为什么“没有可接受的转换”):

#include <iostream>
#include <string>


class Test
{
public:
    operator std::string () const;
};

Test::operator std::string () const
{
    return std::string("Test!");
}

int main ()
{
    std::string str = "Blah!";
    std::cout << str << std::endl;

    Test test;

    str = test;//implicitly calls operator std::string without complaining

    std::cout << str << std::endl;

    std::cout << test;//refuses to implicitly cast test to std::string

    return 0;
}

在 Visual Studio 2010 上出现此错误:“error C2679: binary '&lt;&lt;' : no operator found which takes a right-hand operand of type 'Test' (or there is no acceptable conversion)

&lt;&lt; 运算符是否为了使用它而将std::string 隐式转换为其他东西?如果是,我需要在我的类中重载什么运算符才能使这样的事情起作用?我拒绝相信我真的需要使用operator char *

【问题讨论】:

  • 如果您想直接将Test 实例与ostreams 和&lt;&lt; 一起使用,您应该覆盖正确的方法:msdn.microsoft.com/en-us/library/1z2f6c2k(v=vs.100).aspx
  • @Jack 我认为,OP 更感兴趣的是它为什么不起作用,而不是如何使用完全不同的方法来修复它。

标签: c++ string operator-overloading


【解决方案1】:

operator&lt;&lt;(std::basic_ostream&amp;, std::basic_string) 是一个函数模板,在模板参数推导过程中不考虑用户定义的转换。你需要为你的班级重载operator&lt;&lt;

当然,另一种选择是演员表

std::cout << static_cast<std::string>(test);

【讨论】:

  • “显式转换”是多余的。
  • 并非所有operator&lt;&lt; 都是模板,但string 是模板;它可能值得精确。
  • @MatthieuM。谢谢,已更新。
  • “在模板参数推导过程中不考虑用户定义的转换” - 有趣。所以,基本上,如果我定义operator std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; () const 而不是operator std::string () const;,它应该编译?不幸的是,它似乎也不喜欢它。我只是想更好地理解模板,所以别担心,这永远不会出现在真正的代码中 :)
【解决方案2】:

问题在于std::string 是模板std::basic_string&lt;char&gt; 的特化,而operator&lt;&lt; 所需的重载本身就是模板:

template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>&& os,
               const basic_string<charT,traits,Allocator>& str);

为了用于模板参数推导,用户定义的类型必须完全匹配;不考虑转化。

您需要为您的班级提供operator&lt;&lt; 的重载,或者显式转换为std::string

【讨论】:

  • 出于好奇,为了与上述情况完全匹配,用户定义的类型会是什么样子?我只是想更好地理解模板。
  • @MihaiTodor:要完全匹配,它必须是 std::basic_string 的特化。
【解决方案3】:

一般取决于类的流插入操作符&lt;&lt;是具体函数还是模板。

&lt;&lt;为具体函数,找到重载,完成转换(只要不模棱两可):

#include <iostream>
using namespace std;

template< class CharType >
struct String {};

ostream& operator<<( ostream& stream, String<char> const& s )
{
    return (stream << "s");
}

struct MyClass
{
    operator String<char> () const { return String<char>(); }
};

int main()
{
    cout << "String: " << String<char>() << endl;
    cout << "MyClass: " << MyClass() << endl;
}

但是,使用&lt;&lt;作为函数模板,模板匹配找不到匹配,然后不尝试通过用户定义的运算符进行转换:

#include <iostream>
using namespace std;

template< class CharType >
struct String
{
};

template< class CharType >
ostream& operator<<( ostream& stream, String< CharType > const& s )
{
    return (stream << "s");
}

struct MyClass
{
    operator String<char> () const { return String<char>(); }
};

int main()
{
    cout << "String: " << String<char>() << endl;
    cout << "MyClass: " << MyClass() << endl;       // !Oops, nyet! Not found!
}

在您的情况下,std::string 实际上只是 typedefstd::basic_string&lt;char&gt;

修复:为您的类定义一个 &lt;&lt; 运算符,或者,如果您想避免头文件依赖(考虑构建时间),定义一个转换为例如char const*,或者,最简单也是我推荐的,将该转换设为命名转换,以便必须显式调用它。

显式是好的,隐式是坏的。

【讨论】:

  • +1 for Explicit is good 并显示模板效果并减少测试用例!
  • 所以,也许是一个愚蠢的问题:如果std::string 只是typedef basic_string&lt;char, char_traits&lt;char&gt;, allocator&lt;char&gt; &gt; 并且我在Test 类中定义了operator std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; () const;,为什么它仍然不被视为“完全匹配”?我的意思是,根据您(和其他人)所说的,这应该可以编译,对吧?我真的很想了解它背后的原因。
  • @MihaiTodor:哦,参数推导尝试将MyClass&lt;&lt; 调用的实际参数类型)与std::basic_string&lt;C, T, A&gt;(形式参数类型)匹配,其中CTA 是模板参数。但是没有选择这些参数可以将MyClass 转换为完全匹配或任何类型的匹配。对于模板参数匹配,仅考虑直接、完全匹配,而不考虑任何用户定义的转换。模板参数匹配支持的唯一“转换”是派生到base。
【解决方案4】:

我认为您需要覆盖的运算符是“

【讨论】:

    【解决方案5】:

    您需要重写operator&lt;&lt; 方法。

    std::ostream & operator <<(std::ostream & os, const Test & t) {
        return os << std::string(t);
    }
    

    【讨论】:

      猜你喜欢
      • 2013-09-07
      • 2013-05-11
      • 2013-09-10
      • 2012-10-31
      • 2014-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多