std:: endl имеет неизвестный тип при перегрузке оператора


Я перегруженный оператор

template <Typename T>
UIStream& operator<<(const T);

UIStream my_stream;
my_stream << 10 << " heads";

работает, но:

my_stream << endl;

дает ошибку компиляции:

ошибка C2678: двоичный'

что такое работа вокруг для создания my_stream << endl работы?

6   51  

6 ответов:

std::endl функция и std::cout использует его реализации operator<< чтобы взять указатель функции с той же сигнатурой, что и std::endl.

там, он вызывает функцию и передает возвращаемое значение.

вот пример кода:

#include <iostream>

struct MyStream
{
    template <typename T>
    MyStream& operator<<(const T& x)
    {
        std::cout << x;

        return *this;
    }


    // function that takes a custom stream, and returns it
    typedef MyStream& (*MyStreamManipulator)(MyStream&);

    // take in a function with the custom signature
    MyStream& operator<<(MyStreamManipulator manip)
    {
        // call the function, and return it's value
        return manip(*this);
    }

    // define the custom endl for this stream.
    // note how it matches the `MyStreamManipulator`
    // function signature
    static MyStream& endl(MyStream& stream)
    {
        // print a new line
        std::cout << std::endl;

        // do other stuff with the stream
        // std::cout, for example, will flush the stream
        stream << "Called MyStream::endl!" << std::endl;

        return stream;
    }

    // this is the type of std::cout
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

    // this is the function signature of std::endl
    typedef CoutType& (*StandardEndLine)(CoutType&);

    // define an operator<< to take in std::endl
    MyStream& operator<<(StandardEndLine manip)
    {
        // call the function, but we cannot return it's value
        manip(std::cout);

        return *this;
    }
};

int main(void)
{
    MyStream stream;

    stream << 10 << " faces.";
    stream << MyStream::endl;
    stream << std::endl;

    return 0;
}

надеюсь, это дает вам лучшее представление о том, как эти вещи работают.

проблема в том, что std::endl - это шаблон функции, как ваш оператор << есть. Поэтому, когда вы пишете:

my_stream << endl;

вы хотите, чтобы компилятор выводил параметры шаблона для оператора как и для endl. Это невозможно.

таким образом, вы должны написать дополнительные, не шаблон, перегрузки оператора << to работа с манипуляторами. Их прототип будет выглядеть так:

UIStream& operator<<(UIStream& os, std::ostream& (*pf)(std::ostream&));

(есть еще два, заменяющие std::ostream by std::basic_ios<char> и std::ios_base, который вы должны предоставить, если вы хотите, чтобы все манипуляторы) и их реализация будет очень похожа на одну из ваш шаблон. На самом деле, так похоже, что вы можете использовать свой шаблон для реализация такова:

typedef std::ostream& (*ostream_manipulator)(std::ostream&);
UIStream& operator<<(UIStream& os, ostream_manipulator pf)
{
   return operator<< <ostream_manipulator> (os, pf);
}

заключительная нота, часто пишущая пользовательский streambuf часто лучший способ достигните того, чего вы пытаетесь достичь, применяя технику, которую вы используете.

Я сделал это, чтобы решить мою проблему, вот часть моего кода:

    template<typename T> 
    CFileLogger &operator <<(const T value)
    {
        (*this).logFile << value;
        return *this;
    }
    CFileLogger &operator <<(std::ostream& (*os)(std::ostream&))
    {
        (*this).logFile << os;
        return *this;
    }

Главная.cpp

int main(){

    CFileLogger log();    
    log << "[WARNINGS] " << 10 << std::endl;
    log << "[ERRORS] " << 2 << std::endl;
    ...
}

Я получил ссылку здесь http://www.cplusplus.com/forum/general/49590/

надеюсь, что это может помочь кому-то.

посмотреть здесь для лучших способов расширения IOStreams. (Немного устарел и адаптирован для VC 6, поэтому вам придется взять его с солью)

дело в том, что для работы функторов (и endl, который одновременно выводит "\n" и сбрасывает функтор) вам нужно реализовать полный интерфейс ostream.

The std потоки не предназначены для подклассов, поскольку у них нет виртуальных методов, поэтому я не думаю, что вы зайдете слишком далеко с этим. Вы можете попробовать агрегировать std::ostream, чтобы выполнить эту работу.

сделать endl работа вам нужно реализовать версию operator<< что принимает указатель на функцию, как это, как манипуляторы, такие как endl обрабатываются, т. е.

UStream& operator<<( UStream&, UStream& (*f)( UStream& ) );

или

UStream& UStream::operator<<( UStream& (*f)( UStream& ) );

теперь std::endl - это функция, которая принимает и возвращает ссылку на std:: basic_ostream, так что не будет работать непосредственно с потоком, так что вам нужно будет сделать свою собственную версию, которая вызывает через std::endl версия в сводные std::iostream.

Edit: похоже, ответ GMan лучше. Он получает std::endl тоже работает!

в дополнение к принятому ответу, с C++11 можно перегрузить operator<< для типа:

decltype(std::endl<char, std::char_traits<char>>)