How to create a lambda for ostream? - c++

I thought the call of the operator<< would generate a two-parameter function call. So, why does this not compile, then?
#include <iostream> // ostream
#include <iomanip> // setw, setfill
using std::ostream; using std::setw; using std::setfill;
struct Clock {
int h_, m_, s_;
Clock(int hours, int minutes, int seconds)
: h_{hours}, m_{minutes}, s_{seconds} {}
void setClock(int hours, int minutes, int seconds) {
h_ = hours; m_ = minutes; s_ = seconds;
}
friend ostream& operator<<(ostream&os, const Clock& c) {
auto w2 = [](ostream&os, int f) -> ostream& {
return os << setw(2) << setfill( '0' ) << f; };
return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_); // ERROR
}
};
The error is (gcc-6)
$ g++-6 -std=gnu++1y ...
file.cpp: In function ‘std::ostream& operator<<(std::ostream&, const Clock&)’:
file.cpp:745:33: error: no match for call to ‘(operator<<(std::ostream&, const Clock&)::<lambda(std::ostream&, int)>) (const int&)’
return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_);
^
I also tried the call os << w2(os,c.h_) but gcc and I agreed that was nonsense. Also I tried the lambda as auto as possible:
auto w2 = [](auto&os, auto f) {
return os << setw(2) << setfill( '0' ) << f; };
also no luck.
Any hints?

I thought the call of the operator<< would generate a two-parameter function call.
No, invoking an overloaded operator<< is basically the same as invoking a binary function:
a << b;
// is equivalent to
operator<<(a, b);
// or to
a.operator<<(b);
What you're trying to do is invoke operator<< using a lambda that returns an ostream& as the right-hand argument, but you're not passing the ostream& argument to the lambda itself.
os << w2(os,c.h_) is syntactically valid, but will not compile because there is no operator<<(ostream&, ostream&) definition.
What you can do is simply invoke the lambda without streaming it:
friend ostream& operator<<(ostream&os, const Clock& c) {
auto w2 = [](ostream&os, int f) -> ostream& {
return os << setw(2) << setfill( '0' ) << f; };
w2(os, c.h_);
os <<':';
w2(os, c.m_);
os << ':';
return w2(os, c.s_);
}
wandbox example
If you want to achieve your desired syntax, you will need a little more work. Here's a possible solution:
template <typename TF>
struct streamable : TF
{
streamable(TF&& f) : TF{std::move(f)} { }
};
template <typename TF>
auto& operator<<(ostream& os, const streamable<TF>& s)
{
s(os); return os;
}
template <typename TF>
auto make_streamable_impl(TF f)
{
return streamable<TF>(std::move(f));
}
template <typename TF>
auto make_streamable(TF f)
{
return [&](auto&& x) mutable
{
return make_streamable_impl([&](ostream& os) -> auto&
{
f(os, x);
return os;
});
};
}
Usage:
friend ostream& operator<<(ostream&os, const Clock& c) {
auto w2 = make_streamable([](ostream&os, int f) -> ostream& {
return os << setw(2) << setfill( '0' ) << f; });
return os << w2(c.h_) <<':'<<w2(c.m_)<<':'<<w2(c.s_);
}
wandbox example
Note that a real implementation should probably perfectly-capture the arguments into the lambdas.

This compiles:
friend ostream& operator<<(ostream&os, const Clock& c) {
auto w2 = [](ostream&os, int f) -> ostream& {
return os << setw(2) << setfill( '0' ) << f; };
return w2( os, c.h_ );
}

Related

Compilation Error in overloading operator

Not able to understand why getting error
error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream’} and ‘MyStruct’)
cout << st;
in the below code
#include <iostream>
using namespace std;
struct MyStruct
{
int a;
string b;
double c;
MyStruct(int a, string b, double c):a(a),b(b),c(c){}
ostream& operator<<(ostream& os)
{
os << "a " << a << " b" << b << " c" << c;
return os;
}
};
template <typename T, typename ... Args>
T create(Args&& ... Arg)
{
return T(Arg...);
}
int main() {
// your code goes here
MyStruct st = create<MyStruct>(5, "My Struct", 2.5);
cout << st;
return 0;
}
The correct signature for the operator is:
friend ostream& operator<<(ostream& os, const MyStruct& dt);
Right now your output stream operator is only overloaded in a way that allows st << cout.

How to call operator template?

I am feeling a bit confused about how to instantiate this template. I know it is gonna be easier to simply use friend membership to realize what I want, but what if I force to do in this way? I just wanna figure it out. (And btw, I know this template seems meaningless), I just want to make it compile.
#include <iostream>
template <typename T>
inline std::ostream& operator<< (std::ostream& os, const T& date)
{
os << date.getD() << " " << date.getM() << " " << date.getY() << "\n";
return os;
}
class Date
{
private:
int dd, mm, yy;
public:
Date(int d, int m, int y) : dd(d), mm(m), yy(y) {}
int getD() const;
int getM() const;
int getY() const;
};
int Date::getD() const { return dd; }
int Date::getM() const { return mm; }
int Date::getY() const { return yy; }
int main(int argc, char const *argv[])
{
Date dat(1, 2, 2003);
std::cout << <Date> dat;
return 0;
}
Two issues:
You're declaring operator<< as template that could accept any types; which would lead to ambiguity issue with std::operator<<.
You can't specify template argument explicitly when calling the operator in operator style. (You can do it in ugly function style like operator<< <Date>(std::cout, dat);) Actually you don't need to specify it, the template parameter could be deduced fine here.
You can change the code to
std::ostream& operator<< (std::ostream& os, const Date& date) {
os << date.getD() << " " << date.getM() << " " << date.getY() <<"\n";
return os;
}
then
Date dat(1,2,2003);
std::cout << dat;
LIVE
but what if I force to do in this way?
As others mentioned, you do not need a template here. But if you insist to do it by templates, you can apply SFINAE to the templated overload of operator<<.
(See live here)
#include <type_traits> // std::enable_if, std::is_same
template <typename T>
auto operator<< (std::ostream& os, const T& date)
-> std::enable_if_t<std::is_same_v<Date, T>, std::ostream&>
{
os << date.getD() << " " << date.getM() << " " << date.getY() << "\n";
return os;
}
This will be done automatically by the compiler. Simply do
int main(int argc, char const *argv[])
{
Date dat(1,2,2003);
std::cout << dat;
return 0;
}
This is done with ADL (Argument-dependent lookup).

explicit specialization for overloading operator '<<' (left shift)

Lets say i have a class, for which i want to overload an operator based on an enum type:
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
/* overload operator '+=' based on 'option' */
template<option E = option::normal>
void operator+=(const foo& f) { i += f.i; }
};
/* explicit specialization for operator += */
template<> void foo::operator+=<option::do_something_stupid>(const foo& f)
{ i += (f.i +1000); }
int main()
{
foo f1(1), f2(2);
f1 += f2;
std::cout << "\nf1 = " << f1.i;
f1.operator+=<option::do_something_stupid>(f2);
std::cout << "\nf1 = " << f1.i;
std::cout << "\n";
return 0;
}
This builds clean (ignoring the fact that it really does something pretty dump) both on g++ and clang++.
What if i want to overload the '<<' operator the same way? A similar approach does not seem to work:
#include <ostream>
#include <iostream>
enum class option : char { normal, do_something_stupid };
class foo
{
public:
int i;
explicit foo(int a=0) : i(a) {};
template<option E = option::normal>
friend std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
};
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
std::cout.operator<< <option::do_something_stupid>(f1);
std::cout << "\n";
return 0;
}
According to g++, the call from main to the operator is invalid:
error: no match for ‘operator<’ (operand types are ‘<unresolved overloaded function type>’ and ‘option’)
std::cout.operator<< <option::do_something_stupid>(f1);
clang++ on the other hand, produces a different error message:
lsfov.cc:20:1: error: 'operator<<' cannot be the name of a variable or data member
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:20:11: error: expected ';' at end of declaration
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
;
lsfov.cc:20:12: error: expected unqualified-id
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:33:15: error: reference to non-static member function must be called
std::cout.operator<< <option::do_something_stupid>(f1);
~~~~~~~~~~^~~~~~~~~~
which goes on listing possible overload of '<<' from the standard library (if i understand correctly), like:
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:108:7: note: possible target for call
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:117:7: note: possible target for call
operator<<(__ios_type& (*__pf)(__ios_type&))
^
What is going on? Is this kind of operator specialization possible/allowed? If so, what is the proper way to call the operator? Or is clang correct and the definition is ill formed?
I think clang doesn't like the declaration of the friend in relation to the specialisation. Re-ordering them does the trick.
enum class option : char { normal, do_something_stupid };
// forward declare the class and operator
class foo;
template<option E = option::normal>
std::ostream& operator<<(std::ostream& o, const foo& f);
// the class with the declared friend operator
class foo
{
private:
int i;
public:
explicit foo(int a=0) : i(a) {};
template<option E>
friend std::ostream& operator<<(std::ostream& o, const foo& f);
};
// the operator implementations
template<option E>
std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}
In addition, the operator<< used in the main is not a member cout, but rather a global.
int main()
{
foo f1(1), f2(2);
std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
operator<< <option::do_something_stupid>(std::cout, f1);
std::cout << "\n";
return 0;
}
Sample here. g++ is also happy with the code as above.
A note on operators in a non-deduced context. I assume you are using the code here in a greater project of some sort, but if the operator is being used with non-deduced parameters, it is often easier and clearer to implement the functionality in a member method or a free function (using friend as required).

Invoking specialized ostream operator

I have the following code...
#include <sstream>
enum class eTag
{
A,
B,
C
};
template<eTag I> std::ostream& operator<< (std::ostream& str, int i)
{
return str; // do nothing
}
template<> std::ostream& operator<< <eTag::A>(std::ostream& str, int i)
{
return str << "A:" << i; // specialize for eTag::A
}
template<> std::ostream& operator<< <eTag::B>(std::ostream& str, int i)
{
return str << "B:" << i; // specialize for eTag::B
}
template<> std::ostream& operator<< <eTag::C>(std::ostream& str, int i)
{
return str << "C:" << i; // specialize for eTag::C
}
int main()
{
std::ostringstream s;
// s << <eTag::A>(42) << std::endl;
return 0;
}
This compiles. But as you can see from the commented line in main(), I'm struggling with how to actually invoke a specialization of the ostream operator.
Quick answer:
operator<< <eTag::A>(std::cout,42);
I think you're much better off with implementing your own template-class manipulator that friends ostream& operator<<(ostream&), and keeps the state as a member variable (initialized via a constructor). See here (except for the template-part)
operator<<<eTag::A>(std::cout, 42) << std::endl;
(You can add a space between operator<< and the template argument list if you want. Doesn't make a difference.)
This is pretty nasty. Usually we don't write operators that require explicit template arguments. Better to do something like this:
inline std::ostream& operator<<(std::ostream& os, eTag x) {
if (x == eTag::A) {
return os << "A:";
} else if (x == eTag::B) {
return os << "B:";
} else if (x == eTag::C) {
return os << "C:";
} else {
throw std::range_error("Out of range value for eTag");
}
}
Then:
std::cout << eTag::A << 42 << std::endl;
A good compiler will be able to inline this, so your code will be as efficient as if you had just typed
std::cout << "A:" << 42 << std::endl;

How can I use cout << myclass

myclass is a C++ class written by me and when I write:
myclass x;
cout << x;
How do I output 10 or 20.2, like an integer or a float value?
Typically by overloading operator<< for your class:
struct myclass {
int i;
};
std::ostream &operator<<(std::ostream &os, myclass const &m) {
return os << m.i;
}
int main() {
myclass x(10);
std::cout << x;
return 0;
}
You need to overload the << operator,
std::ostream& operator<<(std::ostream& os, const myclass& obj)
{
os << obj.somevalue;
return os;
}
Then when you do cout << x (where x is of type myclass in your case), it would output whatever you've told it to in the method. In the case of the example above it would be the x.somevalue member.
If the type of the member can't be added directly to an ostream, then you would need to overload the << operator for that type also, using the same method as above.
it's very easy, just implement :
std::ostream & operator<<(std::ostream & os, const myclass & foo)
{
os << foo.var;
return os;
}
You need to return a reference to os in order to chain the outpout (cout << foo << 42 << endl)
Even though other answer provide correct code, it is also recommended to use a hidden friend function to implement the operator<<. Hidden friend functions has a more limited scope, therefore results in a faster compilation. Since there is less overloads cluttering the namespace scope, the compiler has less lookup to do.
struct myclass {
int i;
friend auto operator<<(std::ostream& os, myclass const& m) -> std::ostream& {
return os << m.i;
}
};
int main() {
auto const x = myclass{10};
std::cout << x;
return 0;
}
Alternative:
struct myclass {
int i;
inline operator int() const
{
return i;
}
};