16

可能重复:
通过隐式转换为字符串流式传输对象时重载解析失败

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

#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 '<<' : no operator found which takes a right-hand operand of type 'Test' (or there is no acceptable conversion)

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

4

5 回答 5

16

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

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

std::cout << static_cast<std::string>(test);
于 2012-12-14T17:05:33.267 回答
11

问题在于这std::string是模板的特化,std::basic_string<char>而所需的重载operator<<本身就是模板:

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<<为您的类提供重载,或显式转换为std::string.

于 2012-12-14T17:09:51.830 回答
5

通常,这取决于<<类的流插入运算符是具体函数还是模板。

作为<<一个具体的函数,找到了重载,并完成了转换(只要它不模棱两可):

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

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

#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实际上只是一个typedeffor std::basic_string<char>

修复:<<为您的类定义一个运算符,或者,如果您想避免头文件依赖(考虑构建时间),定义一个转换为 eg char const*,或者,最简单并且我推荐的,将该转换命名为显式调用。

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

于 2012-12-14T17:15:23.113 回答
0

我认为您需要覆盖的运算符是 "<<" 。

于 2012-12-14T17:04:32.690 回答
0

您需要覆盖该operator<<方法。

std::ostream & operator <<(std::ostream & os, const Test & t) {
    return os << std::string(t);
}
于 2012-12-14T17:05:07.277 回答