Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::endl is of unknown type when overloading operator<<

I overloaded operator <<

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

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

Works but:

my_stream << endl;

Gives compilation error:

error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'UIStream' (or there is no acceptable conversion)

What is the work around for making my_stream << endl work?

like image 690
Kazoom Avatar asked Jul 15 '09 22:07

Kazoom


People also ask

Can << operator be overloaded?

Output streams use the insertion ( << ) operator for standard types. You can also overload the << operator for your own classes.

What is the type of std :: endl?

std::endl. Inserts a new-line character and flushes the stream.

What is operator overloading explain the >> << operator with the help of example?

This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. For example, we can overload an operator '+' in a class like String so that we can concatenate two strings by just using +.

Why must << be overloaded as a friend function?

Why must << be overloaded as a friend function? It is not necessary. It is usually done because this function often accesses the private and protected members of the object it displays. overloaded operator<< or operator>> function.


3 Answers

std::endl is a function and std::cout utilizes it by implementing operator<< to take a function pointer with the same signature as std::endl.

In there, it calls the function, and forwards the return value.

Here is a code example:

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

Hopefully this gives you a better idea of how these things work.

like image 84
GManNickG Avatar answered Oct 07 '22 00:10

GManNickG


The problem is that std::endl is a function template, as your operator << is. So when you write:

my_stream << endl;

you'll like the compiler to deduce the template parameters for the operator as well as for endl. This isn't possible.

So you have to write additional, non template, overloads of operator << to work with manipulators. Their prototype will look like:

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

(there are two others, replacing std::ostream by std::basic_ios<char> and std::ios_base, which you have also to provide if you want to allow all manipulators) and their implementation will be very similar to the one of your templates. In fact, so similar that you can use your template for implementation like this:

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

A final note, often writing a custom streambuf is often a better way to achieve what one try to achieve applying to technique you are using.

like image 37
AProgrammer Avatar answered Oct 06 '22 23:10

AProgrammer


I did this to solve my problem, here is part of my code:

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

Main.cpp

int main(){

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

I got the reference in here http://www.cplusplus.com/forum/general/49590/

Hope this can help someone.

like image 9
Lucas Casagrande Avatar answered Oct 06 '22 22:10

Lucas Casagrande