I'm studying overloaded operators.
I don't get the difference between using the <<-operator on a double / an std::string.
int main()
{
double a = 12;
string s = "example";
operator<<(cout, a); //doesn't work
cout.operator<<(a); //works
operator<<(cout, s); //works
cout.operator<<(s); //doesn't work
}
Why aren't operator<<(cout, a) and cout.operator<<(s); working?
Because that operator is defined as a member function, not as a free function.
Operators can be overloaded in those two ways, which when used with regular operator syntax will be transparent to the user. However, when using explicit syntax, you have to use the one specific to the actual function definition.
This example shows the difference in practice:
class Stream {
Stream& operator<<(Inside);
};
Stream& operator<<(Stream&, Outside);
For std::string, Outside way is used. For double, Inside is.
You can define operators in two different ways, as a member of a class and as free-standing function taking two arguments.
The operator accepting a double value is implemented as a member function of std::ostream, see cpp reference. You'll notice that there is no overload for char const* or std::string provided. These are defined separately, as free-standing functions, among some others.
Those operators defined as members (only!) work with the cout.operator<<(argument) notation, the free-standing ones with the two-argument variant.
However, all these differences are hidden away if you use the operators as they are intended:
std::cout << whatEver;
Because a non-class operator << for the types std::basic_ostream & and double (or const double &) is not defined in C++.
Such an operator that takes one argument of the type double is declared in the class std::basic_ostream as a member function.
basic_ostream<charT, traits>& operator<<(double f);
For objects of the type std::string the operator is declared as a stand-alone (non a class member) function the following way
template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT, traits, Allocator>& str);
std::basic_ostream provides some << implementations (for basic types) as member functions. For other types (such as for std::basic_string), operator << is implemented as a free function. That's how the standard specifies it.
This is only a problem if you're invoking the operator using explicit function call notation (like in your code). The natural way to use it is using operator notation (cout << x), where the problem does not happen, as both member and free functions can be invoked by it.
You are using operator not in the right way.
operators may be implemented as member functions or non-member.
when running
cout.operator <<(a);
cout << a;
cout.operator <<(s);
cout << s;
you are calling the class operarator implementation;
but when you call
operator<<(cout, a);
where is the implementation ? o_O
Working example tested vc++13 & gcc(here)
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main(int argc, char* argv[])
{
int number = 13;
float pi = 3.13f;
double dp = 2.23233;
cout << "number: " << number << endl;
cout << "pi: " << pi << endl;
cout << "double: " << dp << endl << endl;
cout.operator <<(number) << endl;
cout.operator <<(pi) << endl;
cout.operator <<(dp);
}
Comment if need member or non-member implementation of example type.
Related
I wonder, why functional objects in c++ are implemented as templated, with void as default type since c++14.
For example:
https://en.cppreference.com/w/cpp/utility/functional/plus
https://en.cppreference.com/w/cpp/utility/functional/minus
This object in fact performs arithmetic operation +, -, *, /, when called by operator().
The operator() has to be template to work with different types as arguments, but why does the struct have to be?
EDIT
I can create an operator std::plus<>, which may work with a different types in operator():
struct Foo{
int foo;
};
Foo operator+(const Foo& lhs, const Foo& rhs){
return {2 * lhs.foo + 3 * rhs.foo};
}
std::ostream& operator<<(std::ostream& os, const Foo& f){
std::cout << f.foo;
return os;
}
int main()
{
auto op = std::plus<>();
std::cout << op(5, 3) << "\n";
std::cout << op(3.14, 2.71) << "\n";
std::cout << op(Foo(2), Foo(3)) << "\n";
}
And this gives the expected output. Or it may be the case, that having specified the type initially you get something more optimized?
It's a design choice. If you specify the type there is no template operator(), instead the whole class is a template. The operator() is simply something like
constexpr T operator()(const T &lhs, const T &rhs) const
{
return lhs + rhs;
}
This is in several ways different from having a template operator().
If we pass a std::plus<int> it's a plus functor for specifically ints and nothing else.
If we instead passed a std::plus<> without specifying the type it would have a templated operator(). That functor could apply it's operator() to any valid type.
Some advantages with restricting the type from the top of my head:
Since the type is specified the functor can deal with implicit conversion without any issues.
You know for a fact that the functor is not going to silently do things we don't want it to. It's only ever going to do addition on Ts.
Edit
Some examples when the behaviour would differ.
#include <iostream>
#include <functional>
#include <string>
struct Foo {};
int main()
{
auto stringadd = std::plus<std::string>{};
auto anyadd = std::plus<>{};
std::cout << stringadd("hey ", "you") << '\n';
//std::cout << anyadd("hey ", "you") << '\n'; // error: no match for call to '(std::plus<void>) (const char [5], const char [4])'
//std::cout << stringadd("hey ", 1) << '\n'; // error: no match for call to '(std::plus<std::__cxx11::basic_string<char> >) (const char [5], int)'
std::cout << anyadd("hey ", 1) << '\n';
}
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
Because you don't want the function that writes a instance to a stream to modify the instance.
And because a const reference, unlike a non-const one (unless you're using MSVC) can accept a temporary object, which is useful.
IMHO: passing by reference is more efficient than passing via copy and the const keyword stops you from altering the original instance...
in c++ why we declare reference parameter as const in overloaded
function?
No, in the function that you've posted it's done so for the reasons mentioned in the other answers, but there's no requirement i.e. the standard doesn't mandate that an overloaded function taking a reference parameter should be const.
You're mixing up multiple things here. Overloading is a language feature where multiple functions with identical names can coexist, while const is a qualifier which says the data wouldn't change in a given context through that variable/function. They've no relationship that ties them saying it has to be a const if the overloading function takes a reference paramater. The same goes for reference variables too; they're just an alias (a different name) of another variable which has nothing to do with const or function overloading.
a function signature is a contract between the calling code and the function code.
You want that the function will require as less demands as possible.
If you write demanding signature like
ostream &operator<<(ostream &output, Distance &D)
then you won't be able to call your operator from code that operates on const objects:
void Foo(const Distance& d) {
cout << d; // syntax error
}
in other words putting as less requirements as possible on function arguments makes your function more general.
It is not obligatory to define a reference parameter as const in overloaded functions. Simply in your example of the operator << the right operand is not changed in the function. This allows to use this operator with const objects.
For example
#include <iostream>
class Distance
{
public:
//...
friend ostream &operator<<(ostream &output,
const Distance &D)
{
output << "F : " << D.feet << " I : " << D.inches;
return output;
}
private:
float feet;
//...
};
int main()
{
const Distance d1;
std::cout << d1 << std:;endl;
}
The compiler would issue an error parsing statement
std::cout << d1 << std::endl;
if the second parameter in the operator << would be declared as a non-const reference.
Another example
#include <iostream>
struct A
{
A() {}
A( A & ) { std::cout << "A( A & )" << std::endl; }
A( const A & ) { std::cout << "A( const A & )" << std::endl; }
};
int main()
{
A a1;
A a2( a1 );
const A a3;
A a4( a3 );
}
In this example there are two copy constructors one of which defines the parameter as non-const reference and the other defines the parameter as const reference.
If there would not be the second copy constructor then the compiler would issue an error parsing statement
A a4( a3 );
Safety: with const we make sure we won't accidentaly modify the object.
Speed: References are much faster than passing by value. Also const tells the compiler the object won't be modified, therefore some optimizations could be made.
C++
This is an attempt to make a class that mimics the output behavior of using the << operator of an ofstream, as far as being able to use std::endl and write strings is concerned. The class has a single data member, the ofstream pointer. The class has two overloaded << operators, one that takes an std::string and another that takes a pointer to a function, whose argument is an ostream reference and returns an ostream reference. That is the signature of std::endl, according to this. Technically, the below program works with the given input. It is able to print to file, two lines of text separated by two std::endls. However, I want my non-string parameter overloaded << operator to accept std::endl only, not something that merely matches its signature. I tried various combinations of placing std::endlin the argument list, with and without * and with and without &, but I got compiler errors for every combination. C++11 answers are also welcome.
#include <fstream>
#include <iostream>
#include <string>
class TextOut
{
public:
TextOut(std::ofstream* ofsPar) : ofs(ofsPar) {}
TextOut& operator<<(std::string s)
{
*ofs << s;
return *this;
}
TextOut& operator<<(std::ostream& (*endlPar) (std::ostream& os))
{
*ofs << std::endl;
return *this;
}
private:
std::ofstream* ofs;
};
int main()
{
std::cout << "Enter filename: ";
std::string filename;
std::cin >> filename;
std::ofstream myofstream(filename.c_str());
TextOut myTextOut(&myofstream);
myTextOut << "Hello," << std::endl << std::endl << "spacious world.";
return 0;
}
Output:
Hello,
spacious world.
If I look at my ostream header file I see this for endl:
template<typename _CharT, typename _Traits> inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{
return flush(__os.put(__os.widen('\n')));
}
so it looks like you would need to inherit from basic_ostream to make this work. Not sure you really want to do that.
As far as I know there is no way to enforce a parameter to be a specific value at compile time.
If compile-time enforcement is not a requirement, you could use a simple assert like this to enforce that the parameter is std::endl:
assert(static_cast<std::ostream& (*) (std::ostream& os)>(&std::endl) == endlPar);
I need to overload the << operator for streams to work with built-in types. For strings it's not a problem, since I simply overload the function like this:
ostream& operator<<(ostream& os, const char* str) { /*...*/ }
This works because this function is global, not a member. The problem is that I need to overload the << operator for other primitive types (ints, floats, etc) but those are member functions. Is there a way I can do this? I need it to work with not only cout but other streams as well. Thanks in advance.
You shouldn't try to change what the operator in std::cout << 3; does. It's part of a standard API. If you need to output in some format which stream manipulators can't support, then for example you could write a little wrapper:
struct MyFormatter {
MyFormatter (ostream &o) : o(o) {}
ostream &o;
};
MyFormatter &operator<<(MyFormatter &mf, int i) {
mf.o << "int(" << i << ")"; // or whatever
return mf;
}
Then use it like this:
MyFormatter mf(std::cout);
mf << 1 << "," << 2 << "," << 3;
In C++, operator overloads require at least one operand of a "class type" or enumeration type.
The point is you are not allowed to overload operator for primitive types.
http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.10
#include "stdafx.h"
#include "Record.h"
template<class T>//If I make instead of template regular fnc this compiles
//otherwise I'm getting an error (listed on the very bottom) saying
// that operator << is ambiguous, WHY?
ostream& operator<<(ostream& out, const T& obj)
{
out << "Price: "
<< (obj.getPrice()) << '\t'//this line causes this error
<< "Count: "
<< obj.getCount()
<< '\n';
return out;
}
int _tmain(int argc, _TCHAR* argv[])
{
vector<Record> v;
v.reserve(10);
for (int i = 0; i < 10; ++i)
{
v.push_back(Record(rand()%(10 - 0)));
}
copy(v.begin(),v.end(),ostream_iterator<Record>(cout, "\n"));
return 0;
}
//Record class
class Record
{
private:
int myPrice_;
int myCount_;
static int TOTAL_;
public:
Record(){}
Record(int price):myPrice_(price),myCount_(++TOTAL_)
{/*Empty*/}
int getPrice()const
{
return myPrice_;
}
int getCount()const
{
return myCount_;
}
bool operator<(const Record& right)
{
return (myPrice_ < right.myPrice_) && (myCount_ < right.myCount_);
}
};
int Record::TOTAL_ = 0;
Error 2 error C2593: 'operator <<' is ambiguous
The concept behind operator<<( ostream &, ... ) is that every class can have its own overload, handling that specific class in a way that make sense.
That means you get operator<<( ostream &, const Record & ) which handles Record objects, and operator<<( ostream &, const std::string & ) which handles standard strings, and operator<<( ostream &, const FooClass & ) which handles FooClass objects. Each of these functions knows how to handle the object type it has been declared for, because each of them requires a different handling. (E.g. getPrice() / getCount() for Record, or getFoo() / getBar() for FooClass.)
Your template is trampling roughshod over the whole concept. By defining it as a template function (which would match any class), you not only collide with the many definitions of operator<<() already in the standard / your codebase, but all possible overloadings.
How could the compiler decide whether to use operator<<( ostream &, const std::string & ) or your template? It cannot, so it throws up its hands in despair and gives up. That's what the error is telling you.
First, you need to read the error message more carefully. As an alternative, consider breaking the statement up, something like this:
out << "Price: ";
out << (obj.getPrice());
out << "\tCount: ";
out << obj.getCount();
out << '\n';
When you do, you'll realize that what's really causing the problem is not where you try to print out getPrice(), but where you try to print out "Price: ".
The problem is arising because the compiler doesn't know whether to use the normal overload to print out the string, or to use the template being defined to print it out. The latter would cause infinite recursion, and it couldn't actually compile since it requires an object on which you can/could call getPrice and getCount to compile correctly -- but it has a signature that matches, so the compiler says it's ambiguous, and that's the end of that.
The reason of the error is that your templated overload is conflicting with another templated overload, and there is no reason to prefer one template to another:
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
template <class T>
basic_ostream<char, char_traits<char> >& operator<< (basic_ostream<char, char_traits<char> >&, const T&);
//which one is preferable when you ask for: cout << "literal";?
(ostream should be a typedef for basic_ostream<char, char_traits<char> >.)
The whole idea of making your overload a template is questionable, seeing that the overload clearly cannot handle any other class than your Record.
There probably are techniques to allow you to provide a single templated overload for a number of unrelated Record-like classes with a little template metaprogramming (enable_if and traits), if that is the idea.