Как определить операторы вставки для всех манипуляторов COS IOStream?

Все,

Почему следующий код не компилируется для 'std::endl', но он подходит для всех остальных вставленных типов?

#include <sstream> // ostringstream

/// @brief A class that does streamed, formatted output via 'operator<<'.
class My_Stream
{
public:
    /// @brief A member method that manipulates the underlying stream.
    void foo()
    {
        m_oss << "foo_was_here; ";
    }

private:
    /// @brief The underlying stream.
    std::ostringstream m_oss;

    /// @brief 'operator<<' is a friend.
    template< typename T >
    friend My_Stream& operator<<( My_Stream& a_r_my_stream,
                                  const T& a_r_value );
};

/// @brief A manipulator that calls a class method.
My_Stream& manipulator_foo( My_Stream& a_r_my_stream )
{
    a_r_my_stream.foo();
    return a_r_my_stream;
}

/// @brief The generic insertion operator.
template< typename T >
My_Stream& operator<<( My_Stream& a_r_my_stream,
                       const T& a_r_value )
{
    a_r_my_stream.m_oss << a_r_value;
    return a_r_my_stream;
}

/// @brief Define an iostream-like manipulator for my-stream.
typedef My_Stream& ( * my_stream_manipulator ) ( My_Stream& );

/// @brief The specialized 'my_stream_manipulator' insertion operator.
template<>
My_Stream& operator<<( My_Stream& a_r_my_stream,
                       const my_stream_manipulator& a_r_manipulator )
{
    return a_r_manipulator( a_r_my_stream );
}

int main( int argc, char* argv[] )
{
    My_Stream my_stream;

    my_stream << 'c'; // char
    my_stream << "string"; // c-string
    my_stream << 1u; // unsigned int
    my_stream << -1; // signed int
    my_stream << 5.3f; // float
    my_stream << -23.345; // double
    my_stream << std::boolalpha; // std::ios_base manipulator
    my_stream << std::endl; // std::ostream manipulator
    my_stream << manipulator_foo; // my_stream manipulator

    return 0;
}

Я получаю следующую ошибку G++ 4.5:

willo: ~ / test_cpp $ g ++ -Wall test_overloaded_insertion_manipulators.cpp test_overloaded_insertion_manipulators.cpp: в функции 'int main(int, char**)': test_overloaded_insertion_manipulators.cpp:60: ошибка: нет соответствия для "оператора<<" в "my_stream <"

Я ожидаю, что код создаст экземпляр 'operator<<' для std:: endl, как это было сделано для примитивов, std:: ios_base и моего пользовательского манипулятора.

Для контекста я пытаюсь создать IOStream-подобный класс с легким API, который работает с текущими манипуляторами IOStream, а также с одним или двумя пользовательскими манипуляторами.

2 ответа

Решение

Так как endl это шаблон функции:

template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

Таким образом, сам идентификатор не является значением. Он становится значением (указателем на функцию) только тогда, когда создается его экземпляр. Но твой operator<< сам по себе является шаблоном, и нет никакой информации о типах, доступной для компилятора, чтобы решить, какие типы создавать endl с.

В отличие, например, boolalpha является:

ios_base& boolalpha(ios_base& str);

Следовательно, почему это работает.

endl работает на basic_ostreamпотому что тот определяет operator<< перегрузки как функции-члены, принимающие указатели на функции; особенно:

basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));

Так в звонке вроде stream << endlбыло бы знать charT а также traits от типа this (т.е. слева от оператора), и это даст ему точный тип указателя на функцию, ожидаемый с правой стороны - который он затем будет использовать для создания экземпляра соответствующей версии endl, Вы можете сделать то же самое для своего класса.

Вам нужно определить потоковые манипуляторы как отдельного друга.

Добавить этого друга:

// Note: Untested (don't have a compiler here).
template <class charT, class Traits>
friend My_Stream& operator<<( My_Stream&, std::basic_ostream<charT, Traits>& (*)(std::basic_ostream<charT, Traits>&));

Затем вам нужно определить функцию:

template <class charT, class Traits>
My_Stream& operator<<( My_Stream& stream, std::basic_ostream<charT, Traits>& (*manip)(std::basic_ostream<charT, Traits>&))
{
    (*manip)(stream.m_oss);
    return stream;
}
Другие вопросы по тегам