Overload Handling of Std::Endl

Overload handling of std::endl?

What you need to do is write your own stream buffer: When the stream buffer is flushed you output you prefix characters and the content of the stream.

The following works because std::endl causes the following.

  1. Add '\n' to the stream.

  2. Calls flush() on the stream

  3. This calls pubsync() on the stream buffer.

    1. This calls the virtual method sync()
    2. Override this virtual method to do the work you want.
#include <iostream>
#include <sstream>

class MyStream: public std::ostream
{
// Write a stream buffer that prefixes each line with Plop
class MyStreamBuf: public std::stringbuf
{
std::ostream& output;
public:
MyStreamBuf(std::ostream& str)
:output(str)
{}
~MyStreamBuf() {
if (pbase() != pptr()) {
putOutput();
}
}

// When we sync the stream with the output.
// 1) Output Plop then the buffer
// 2) Reset the buffer
// 3) flush the actual output stream we are using.
virtual int sync() {
putOutput();
return 0;
}
void putOutput() {
// Called by destructor.
// destructor can not call virtual methods.
output << "[blah]" << str();
str("");
output.flush();
}
};

// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(std::ostream& str)
:std::ostream(&buffer)
,buffer(str)
{
}
};

int main()
{
MyStream myStream(std::cout);
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}
> ./a.out
[blah]123
[blah]56
[blah]78
>

no match for ‘operator ’ for std::endl after overload

Simple overloading does explain this error. In fact, std::cout just complicates the issue. The following also doesn’t work:

int main(){
my_ostream s;
s << 1;
}

The issue is that your operator << overload in effect hides all the overloads that are defined for the base class.

Roughly speaking, C++ does overload resolution after scope resolution. So C++ first checks if there’s an operator << defined in the scope of your class. There is! So it stops searching for more general functions right there and only considers the functions already found for overload resolution. Alas, there’s only a single overload, for std::string so the call fails.

This can be fixed simply by defining operator << not as a member function but a free function:

my_ostream& operator<<(my_ostream& out, const std::string &s) {
std::cout << out.prefix << s;
return out;
}

… but of course this only fixes some of your problems because your class definition is simply semantically wrong; you cannot subclass the IO streams like this. Here my knowledge fails but I think in order to do what you want you should override the stream buffer’s uflow function.

std::endl is of unknown type when overloading operator

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.

How to avoid an invalid overload from the std library?

The problem can be solved by only overloading the function for 3 or more arguments like:

template<typename T, typename...A>
constexpr inline T const& max(T const&x, T const&y, T const&z, A&&...w)
{
return max(max(x,y), z, std::forward<A>(w)...);
}

Using std::endl in ostream ' '-operator overload with variadic template class containing a variant member leads to compiler error

std::endl is a function template, so has overloads.

With

std::cout << std::endl;

we have to take (correct) address of an overloaded function.

For this, we have to see between each operator<< is there is some which constraint the signature.

There is indeed the ones from basic_stream, in particular

basic_ostream& operator<<(
std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );

(which is the expected best match).

but we also have to check other, in particular, the problematic one:

template<typename... VARIANT_TYPES>
std::ostream& operator<<(std::ostream& os, const VariantContainer<VARIANT_TYPES...>& inst);

and as VARIANT_TYPES would not be deducible from function set, VARIANT_TYPES is empty pack.

Now checking if VariantContainer<>(std::endl) would force signature of the function, so instantiate VariantContainer<> constructors which does hard error due to std::variant<>.

Now possible solutions should avoid hard error with

template<typename... VARIANT_TYPES>
std::ostream& operator<<(std::ostream& os, const VariantContainer<VARIANT_TYPES...>& inst);
  • providing (valid or even incomplete) specialization for class VariantContainer<>

  • Changing primary template to

template <typename T, typename... Ts> 
class VariantContainer;

(no need to change operator <<, as SFINAE will apply to invalid VariantContainer<>)

  • Changing operator<< to
template <typename T, typename... VARIANT_TYPES>
std::ostream& operator<<(std::ostream& os, const VariantContainer<T, VARIANT_TYPES...>& inst);

Dummy debug class stuck on std::endl overload

You can't write decltype(&std::endl) because std::endl isn't a function, it's a function template:

template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& endl( std::basic_ostream<CharT, Traits>& os );

As such, it doesn't have a type, so it doesn't make sense to ask for it. Moreover, even if it did have a type, the subsequent result_of wrapping wouldn't make any sense.

The reason that std::cout << std::endl works is that there is an overload that accepts a specific type of function pointer:

basic_ostream& operator<<(
std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );

This operator is not a function template (it is a member function of basic_ostream, which is a class template), and so overload resolution here triggers instantiation of a specialization of endl.

To get this to work, you should just do the same thing:

dummy_cout& operator<<( std::ostream&(*p)(std::ostream&) );

or pick some appropriate CharT and Traits for your dummy type:

dummy_cout& operator<<( std::basic_ostream<C,T>&(*p)(std::basic_ostream<C,T>& ) );

Just a note. This declaration is ill-formed any C++ standard:

dummy_cout& operator<<(auto& obj);

Terse function template syntax is a feature of the Concepts TS, which is still a TS. Unless you're using -fconcepts, you need to write:

template <class T>
dummy_cout& operator<<(T& obj);

Overloading std::begin() and std::end() for non-arrays

Let's get a complete, reproducible example:

#include <iterator>

char* begin(char& c) { return &c; }
char* end(char& c) { return &c + 1; }

namespace ns {
void my_algorithm(char *first, char *last);

void my_function() {
using std::begin;
using std::end;

char c = '0';
my_algorithm(begin(c), end(c));
}
}

When you make the unqualified call to begin(c) and end(c), the compiler goes through the process of unqualified name lookup (described on the Argument-dependent lookup page of cppreference).

For regular unqualified name lookup, the process is roughly to start at the namespace you are currently in—::ns in this case—and only move out a namespace if you don't find the specific name.

If a function call is unqualified, as it is here with begin(c) and end(c), argument dependent lookup can occur, which finds free functions declared in the same namespace as the types of the functions' arguments, through the process of extending the overload set by finding "associated namespaces."

In this case, however, char is a fundamental type, so argument dependent lookup doesn't allow us to find the global ::begin and ::end functions.

For arguments of fundamental type, the associated set of namespaces and classes is empty

cppreference: argument dependent lookup

Instead, as we already have using std::begin; using std::end;, the compiler already sees possible functions for begin(...) and end(...)—namely those defined in namespace ::std—without having to move out a namespace from ::ns to ::. Thus, the compiler uses those functions, and compilation fails.


It's worth noting that the using std::begin; using std::end; also block the compiler from finding the custom ::begin and ::end even if you were to place them inside ::ns.


What you can do instead is write your own begin and end:

#include <iterator>

namespace ns {
char* begin(char& c) { return &c; }
char* end(char& c) { return &c + 1; }

template <typename T>
auto begin(T&& t) {
using std::begin;
// Not unbounded recursion if there's no `std::begin(t)`
// or ADL `begin(t)`, for the same reason that our
// char* begin(char& c); overload isn't found with
// using std::begin; begin(c);
return begin(t);
}

template <typename T>
auto end(T&& t) {
using std::end;
return end(t);
}

void my_algorithm(char *first, char *last);

void my_function() {
char c = '0';
my_algorithm(ns::begin(c), ns::end(c));
}
}

How to overload operator with a function as parameter (like endl for cout)?

In order to use foo with overload

CSampleClass& operator << (CSampleClass& (*pf)(CSampleClass&));

it needs to be a non-member function or a static member function.



Related Topics



Leave a reply



Submit