Неявное преобразование в std::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 '<<' : no operator found which takes a right-hand operand of type 'Test' (or there is no acceptable conversion)"

Является ли оператор << неявным образом отбрасывает std::string в нечто другое, чтобы использовать его? Если да, то какой оператор мне нужно перегружать в моем классе, чтобы это работало? Я отказываюсь верить, что мне действительно нужно использовать operator char *.

Ответ 1

operator<<(std::basic_ostream&, std::basic_string) - это шаблон функции, и пользовательские преобразования не учитываются при выводе аргумента шаблона. Вам нужно перегрузить operator<< для вашего класса.

Другим вариантом, конечно же, является литой

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

Ответ 2

Проблема заключается в том, что 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.

Ответ 3

В общем случае это зависит от того, является ли оператор вставки потока << для класса конкретной функцией или шаблоном.

С << в качестве конкретной функции найдена перегрузка и выполняется преобразование (если оно не является двусмысленным):

#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 на самом деле просто typedef для std::basic_string<char>.

Исправить: определить оператор << для вашего класса или, если вы хотите избежать зависимости заголовка (время построения мышью), определить преобразование, например. char const*, или, что проще и что я рекомендую, сделайте это преобразование именованным так, чтобы он был явно вызван.

Явный хороший, неявный плохо.

Ответ 4

Я думаю, что оператор, который вам нужно переопределить, равен "< <".

Ответ 5

Вам нужно переопределить метод operator<<.

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