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.
Add
'\n'
to the stream.Calls
flush()
on the streamThis calls
pubsync()
on the stream buffer.- This calls the virtual method
sync()
- Override this virtual method to do the work you want.
- This calls the virtual method
#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
Sorting Two Corresponding Arrays
Linux Equivalent for Conio.H Getch()
What Are the Distinctions Between the Various Symbols (*,&, etc) Combined with Parameters
Why Stdfax.H Should Be the First Include on Mfc Applications
Variable Declarations in Header Files - Static or Not
Does Boost Have a Datatype for Set Operations That Is Simpler Than the Stl
Reorder Vector Using a Vector of Indices
Undefined Reference Error for Template Method
Do I Really Need to Implement User-Provided Constructor for Const Objects
Cin for an Int Inputing a Char Causes Loop That Is Supposed to Check Input to Go Wild
How to Get a List of Video Capture Devices (Web Cameras) on Linux ( Ubuntu )? (C/C++)
Gdb Shows Incorrect Arguments of Functions for Stack Frames
Why How to Not Brace Initialize a Struct Derived from Another Struct
How to Reset Std::Cin When Using It
Explain C++ Sfinae to a Non-C++ Programmer
Floating Point Comparison Revisited