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.
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';
}
I am trying to make a polymorphic vector using std::reference_wrapper for these classes:
struct Int2TypeBase{
virtual void which(){ std::cout << "Int2TypeBase" << "\n";}
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
void which(){ std::cout << "Int2Type<" << value << ">""\n";}
friend bool operator==(const Int2Type& lhs, const Int2Type& rhs){
return lhs.v == rhs.v;
}
};
Now I am trying to make use of std::reference_wrapper like this:
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
auto x = v[0];
x.get().which();
std::cout << typeid(x.get()).name() << "\n";
// std::cout << (x.get() == i2t_1) << "\n";
}
The output is:
Int2Type<0>
8Int2TypeILi0EE
This is what I would expect.
Now however, when I uncomment std::cout << (x.get() == i2t_1) << "\n"; I will get
invalid operands to binary expression ('Int2TypeBase' and 'Int2Type<0>')
This confuses me, as typeid(x.get()).name() returned 8Int2TypeILi0EE rather than F12Int2TypeBasevE which is what I get for typeid(Int2TypeBase()).name();. Furthermore which() also was called for the derived class... so then why does x.get() in x.get() == i2t_1 evaluate to a Int2TypeBase?
Your comparison operator is only defined for derived classes, but the reference wrapper produces (static) type Int2Base, so overload resolution does not even find your comparison operator!
What you probably need is a comparison operator of the form
bool operator==(const Int2TypeBase& lhs, const Int2TypeBase& rhs)
but then you also need to have some sort of polymorphic dispatch to perform the actual comparison (presumably assuming that the dynamic types match).
At compile time, the compiler can only tell that the type of x.get() is Int2TypeBase, because as declared you can put any Int2TypeBase there. So at compile time, it can't determine that the == operator will work.
At run time, the objects you put in the collection reference their full type, so typeid returns what you expect and the correct virtual function is called.
I was trying to write some operator overload functions, especially the << operator to use it with a custom class and an std::ofstream object, but I was a bit confused by the syntax used in various examples found online. For example, let's consider the operator<< overload as a non-member function for a simple custom class:
#include <fstream>
class Example {
public:
int first;
int second;
};
// I found this kind of operator on the Internet
std::ofstream& operator<< (std::ofstream& out, Example obj) {
out << obj.first << endl << obj.second;
return out;
}
int main() {
Example a={1,2};
std::ofstream out;
out.open("test");
out << a;
out.close();
}
I don't really get why It should return std::ofstream& to work properly. I tried using the following operator
void operator<< (std::ofstream& out, Example obj) {
out << obj.first << endl << obj.second << endl;
}
and it worked as well. I mean, can't out << obj; be interpreted as operator<< (out , obj); ? Why does it have to return something since I'm passing a reference to the std::ofstream object?
The same doubt arose when I was trying to write an operator= overload as a member function for a custom class, as the simple example that follows
class Custom{
public:
int up;
int down;
Custom& operator= (Custom a) {
up=a.up;
down=a.down;
return *this;
}
};
I used the copy-swap idiom for the assignment operator, so don't mind the operator definition too much, it's just an example. Again, writing
Custom obj1, obj2;
obj1 = obj2;
since I can interpret obj1 = obj2; as obj1.operator=(obj2), why is the return type Custom& required instead of void?
If you want to be able to chain operator<<s together, you have to use a return type (better std::ostream& than std::ofstream&, so you can use it for std::cout and like, too).
out << a << b;
(out << a) << b;
^^^^^^^^^^
lhs has to be a stream
For assignment operator, the reason is essentially the same. C++ syntax allows you to write many expressions requiring the return type, for example this:
Custom obj1, obj2, obj3;
(obj1 = obj2) + obj3 ... // assign obj2 to obj1 and work with that...
Returning a reference allows you to chain the operators, like
std::cout << e1 << e2;
Return a reference instead of void, make it possible to write like
out << obj1 << obj2 << obj3;
For operator=, you can write
obj1=obj2=obj3;
You can write somthing like cout << "First operand" << "Second operand" because first operand returns reference to ostream and second operand works with this reference.
operator= works same way. You can write a = b = c, but also you can put it inside if (a = b) or while (a = b). This can make your code shorter, but is a little dangerous.
There are 2 function overloads:
MyClass do_something(MyClass param);
const MyClass& do_something(const MyClass& param);
Then I do:
MyClass c1 {"c1"};
do_something(c1); // I want this to be used by value overload
do_something(c1); // this to be used by reference overload
Is there any special way to explicitly specify that argument is passed by value or by reference?
For move semantic there is std::move() I wonder if there is anything like std::copy() std::ref for my case?
P.S. It's not to be used in real program, just checking out by myself the difference of passing arguments, returning values and their behaviour in different ways and have all functions with the same name:
// pass by value (copy)
MyClass do_something(MyClass param) {
cout << "do_something(MyClass param)" << endl;
param.i = 100;
return param;
}
// !!! Your normal habit when passing an argument to a function should be to pass by const reference. (thinking in c++)
// pass by reference (reference)
const MyClass& do_something(const MyClass& param) { // doesn't allow to modify the object
cout << "do_something(MyClass& param)" << endl;
return param;
}
// pass by move semantic (move)
MyClass&& do_something(MyClass&& param) {
cout << "do_something(MyClass&& param)" << endl;
param.name += "__after_do_something(MyClass&& param)";
param.i = 100;
return move(param);
}
// pass by pointer (reference)
MyClass* do_something(MyClass* const param) { // allows to modify object, but not pointer (address)
cout << "do_something(MyClass* const param)" << endl;
param->i = 100;
// (*param).i = 100; // the same as above
return param;
}
You can resolve an overload ambiguity by casting to the relevant function pointer type (it's one of the rare cases where the type of an expression is determined by outer context, instead of being built up from inside):
struct MyClass { char const* s; };
MyClass do_something(MyClass) { return MyClass(); }
const MyClass& do_something(const MyClass& param) { return param; }
auto main() -> int
{
MyClass c1 {"c1"};
static_cast<MyClass(*)(MyClass)>( do_something )( c1 ); // Value overload
static_cast<MyClass const&(*)(MyClass const&)>( do_something )( c1 ); // Ref overload
}
But in practice you should just name the functions differently, or use tie-breaker arguments or argument types, i.e., designing the functions for explicit choice of function.
I would name them differently because they do different things, so it indicates the Wrong Thing™ to have the same name for them.
Is there any special way to explicitly specify that argument is passed by value or by reference?
No, but there are workaround.
With template method and specialization, you may explicitly tell which version you want:
template <typename T>
T do_something(T);
template<>
MyClass do_something(MyClass) { std::cout << "value" << std::endl; }
template<>
const MyClass& do_something(const MyClass&)
{
std::cout << "reference" << std::endl;
}
And then call it:
do_something<MyClass>(c); // value
do_something<const MyClass&>(c); // reference
do_something(c); // value
Live Demo
But it would be simpler/cleaner to create overload with explicit tag:
struct by_value{};
struct by_ref{};
MyClass do_something(MyClass, by_value) { std::cout << "value" << std::endl; }
const MyClass& do_something(const MyClass&, by_ref)
{
std::cout << "reference" << std::endl;
}
And call it
do_something(c, by_value{}); // value
do_something(c, by_ref{}); // reference
Is there any special way to explicitly specify that argument is passed by value or by reference?
Yes. If it is not copyable (i.e., deleted or private copy constructor) it can only be passed by reference.
Assuming following code. There is class MyStream witch has template overloaded operator <<. There also is globally overloaded operator MyStream& operator << (MyStream&, const MyClass&). The confusing thing is generating (by compiler) different methods for two almost identical situations (see body of main() function). I supposed that global operator should be used in both cases but it isn't. Why so?
#include <iostream>
class MyStream;
class MyClass;
MyStream& operator << (MyStream& stream, const MyClass&);
class MyStream
{
public:
template <typename T>
MyStream& operator << (const T&)
{
std::cout << __FUNCTION__ << " " << typeid(T).name() << std::endl;
return *this;
}
};
class MyClass
{
};
MyStream& operator << (MyStream& stream, const MyClass&)
{
std::cout << __FUNCTION__ << " " << typeid(MyClass).name() << std::endl;
return stream;
}
int main(int, char**)
{
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
std::cout << std::endl;
// 2. Template instantiation
MyStream() << MyClass();
std::cin.get();
return 0;
}
Output of program compiled with Microsift Visual C++ Compilers 9.0 (x86):
MyStream::operator << int
operator << class MyClass
MyStream::operator << class MyClass
// 2. Template instantiation
MyStream() << MyClass();
In this case, the expression MyStream() creates a temporary object (a rvalue) which cannot be bound to non-const reference, so the compiler chooses the member function template, because in order to call the free function, the temporary object must be passed as first argument to the function, which is not possible here, as the type of first parameter of the free function is non-const reference. So MyStream << MyClass() invokes member function.
But when you write this:
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
It first invokes the member function passing int(), and the member function returns an object of type MyStream& which now can be passed to free function as first argument (as it is no more a rvalue, it is now a lvalue), then it invokes the free function, passing object of type MyStream& as first argument and MyClass() as second argument.
This is interesting, and a similar thing happens here:
std::ostringstream printing the address of the c-string instead of its content