Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 73cc7a5b authored by ROUVREAU Vincent's avatar ROUVREAU Vincent
Browse files

Merge branch 'input_stream_operator_example_ennhancement' into 'master'

operator>> example enhancement to mention chained calls

See merge request formations/cpp/gettingstartedwithmoderncpp!52
parents e55eb2ee 83c44962
No related branches found
No related tags found
1 merge request!52operator>> example enhancement to mention chained calls
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Operators](./0-main.ipynb) - [Stream operators](./3-Stream.ipynb) # [Getting started in C++](./) - [Operators](./0-main.ipynb) - [Stream operators](./3-Stream.ipynb)
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1> <h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Operator-<<" data-toc-modified-id="Operator-<<-1">Operator &lt;&lt;</a></span></li><li><span><a href="#Operator->>" data-toc-modified-id="Operator->>-2">Operator &gt;&gt;</a></span></li></ul></div> <div class="toc"><ul class="toc-item"><li><span><a href="#Operator-<<" data-toc-modified-id="Operator-<<-1">Operator &lt;&lt;</a></span></li><li><span><a href="#Operator->>" data-toc-modified-id="Operator->>-2">Operator &gt;&gt;</a></span></li></ul></div>
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Operator << ## Operator <<
So far, we have very often defined methods and/or functions named `Print()` to provide a visual printing of the content of a class. So far, we have very often defined methods and/or functions named `Print()` to provide a visual printing of the content of a class.
However, it's even better if we could use the `<<` syntax directly, and the way to do so is to provide an overload of `operator<<`. However, it's even better if we could use the `<<` syntax directly, and the way to do so is to provide an overload of `operator<<`.
The recommended way to implement it is to use under the hood a `Print(std::ostream&)` (or whatever you want to call it): The recommended way to implement it is to use under the hood a `Print(std::ostream&)` (or whatever you want to call it):
**Xeus-cling** issue: cling doesn't accept operator definition outside of class; please use [@Coliru](https://coliru.stacked-crooked.com/a/04f59249cce6c131) **Xeus-cling** issue: cling doesn't accept operator definition outside of class; please use [@Coliru](https://coliru.stacked-crooked.com/a/04f59249cce6c131)
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
// Doesn't run on Xeus-cling due to definition of an operator outside of a class // Doesn't run on Xeus-cling due to definition of an operator outside of a class
// A ticket has been opened for this: https://github.com/QuantStack/xeus-cling/issues/214 // A ticket has been opened for this: https://github.com/QuantStack/xeus-cling/issues/214
#include <iostream> #include <iostream>
class Rational class Rational
{ {
public : public :
explicit Rational(int numerator, int denominator); explicit Rational(int numerator, int denominator);
// Might even be private; in which case friendship needs to be declared // Might even be private; in which case friendship needs to be declared
void Print(std::ostream& out) const; void Print(std::ostream& out) const;
private : private :
int numerator_ = 0; int numerator_ = 0;
int denominator_ = 0; int denominator_ = 0;
}; };
Rational::Rational(int numerator, int denominator) Rational::Rational(int numerator, int denominator)
: numerator_(numerator), : numerator_(numerator),
denominator_(denominator) denominator_(denominator)
{ } { }
void Rational::Print(std::ostream& out) const void Rational::Print(std::ostream& out) const
{ {
out << numerator_ << " / " << denominator_; out << numerator_ << " / " << denominator_;
} }
std::ostream& operator<<(std::ostream& out, const Rational& r) std::ostream& operator<<(std::ostream& out, const Rational& r)
{ {
r.Print(out); // see how the bulk of the work is done by the 'Print()' method! r.Print(out); // see how the bulk of the work is done by the 'Print()' method!
return out; return out;
} }
int main() int main()
{ {
Rational r1(22, 7); Rational r1(22, 7);
Rational r2(77, 17); Rational r2(77, 17);
std::cout << "Rational = " << r1 << std::endl; std::cout << "Rational = " << r1 << std::endl;
std::cout << "Call may also be chained due to the signature of the function: " << r1 std::cout << "Call may also be chained due to the signature of the function: " << r1
<< " and " << r2 << std::endl; << " and " << r2 << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Please notice the slightly weird expected syntax for the `operator<<`: the `std::ostream` appears actually twice; the reason for that is to enable chained calls: Please notice the slightly weird expected syntax for the `operator<<`: the `std::ostream` appears actually twice; the reason for that is to enable chained calls:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
// Doesn't run on Xeus-cling! // Doesn't run on Xeus-cling!
int main() int main()
{ {
Rational r1(22, 7); Rational r1(22, 7);
Rational r2(84, 9); Rational r2(84, 9);
std::cout << "Rationals = " << r1 << " and " << r2 << std::endl; std::cout << "Rationals = " << r1 << " and " << r2 << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
## Operator >> ## Operator >>
`operator>>` might be overloaded in a similar way; it might be used for instance to create an object from data read in a file. As usual with `operator>>`, you should be cautious and handle well the case in which the flux becomes invalid: `operator>>` might be overloaded in a similar way; it might be used for instance to create an object from data read in a file. As usual with `operator>>`, you should be cautious and handle well the case in which the flux becomes invalid:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` C++17 ``` C++17
// Doesn't run on Xeus-cling due to definition of an operator outside of a class // Doesn't run on Xeus-cling due to definition of an operator outside of a class
// A ticket has been opened for this: https://github.com/QuantStack/xeus-cling/issues/214 // A ticket has been opened for this: https://github.com/QuantStack/xeus-cling/issues/214
#include <iostream> #include <iostream>
class Rational class Rational
{ {
public : public :
explicit Rational(int numerator, int denominator); explicit Rational(int numerator, int denominator);
void Print(std::ostream& out) const; void Print(std::ostream& out) const;
friend std::istream& operator>>(std::istream& in, Rational& r); friend std::istream& operator>>(std::istream& in, Rational& r);
private: private:
//! Set method to modify numerator and denominator. I made the arbitrary choice to make it private //! Set method to modify numerator and denominator. I made the arbitrary choice to make it private
//! to illustrate friendship. //! to illustrate friendship.
void Set(int numerator, int denominator); void Set(int numerator, int denominator);
private : private :
int numerator_ = 0; int numerator_ = 0;
int denominator_ = 0; int denominator_ = 0;
}; };
Rational::Rational(int numerator, int denominator) Rational::Rational(int numerator, int denominator)
: numerator_(numerator), : numerator_(numerator),
denominator_(denominator) denominator_(denominator)
{ } { }
void Rational::Print(std::ostream& out) const void Rational::Print(std::ostream& out) const
{ {
out << numerator_ << " / " << denominator_; out << numerator_ << " / " << denominator_;
} }
std::ostream& operator<<(std::ostream& out, const Rational& r) std::ostream& operator<<(std::ostream& out, const Rational& r)
{ {
r.Print(out); r.Print(out);
return out; return out;
} }
void Rational::Set(int numerator, int denominator) void Rational::Set(int numerator, int denominator)
{ {
numerator_ = numerator; numerator_ = numerator;
denominator_ = denominator; denominator_ = denominator;
} }
std::istream& operator>>(std::istream& in, Rational& r) std::istream& operator>>(std::istream& in, Rational& r)
{ {
int numerator {}, denominator {}; int numerator {}, denominator {};
in >> numerator; in >> numerator >> denominator; // Notice the operator>> chained call
in >> denominator;
if (!in) if (!in)
{ {
// If istream is bad; do not modify 'r' // If istream is bad; do not modify 'r'
return in; return in;
} }
r.Set(numerator, denominator); // ok due to friendship! r.Set(numerator, denominator); // ok due to friendship!
return in; return in;
} }
int main() int main()
{ {
Rational r1(22, 7); Rational r1(0,0);
Rational r2(77, 17);
std::cout << "Rational = " << r1 << std::endl;
std::cout << "Call may also be chained due to the signature of the function: " << r1 << " and " << r2 << std::endl;
std::cout << "Enter a rational by separating calls by a space" << std::endl; std::cout << "Enter a rational by separating calls by a space" << std::endl;
std::cin >> r1; std::cin >> r1;
if (std::cin) if (std::cin)
std::cout << "Value read is " << r1 << std::endl; std::cout << "Value read is " << r1 << std::endl;
else else
std::cout << "Invalid input!" << std::endl; std::cout << "Invalid input!" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
This code doesn't run neither in Xeus-cling (due to the operator bug) nor in [Coliru](https://coliru.stacked-crooked.com/) or [Wandbox](https://wandbox.org/) (due to limited `std::cin` support) but you may check it on a local installation. This code doesn't run neither in Xeus-cling (due to the operator bug) nor in [Coliru](https://coliru.stacked-crooked.com/) or [Wandbox](https://wandbox.org/) (due to limited `std::cin` support) but you may check it on a local installation.
Even then, it is not perfect: it handles correctly the case gibberish is given through `std::cin`, but if you put more than two blocks separated by spaces the first two ones are used and the others aren't dealt with... As I said, proper and complete handling of input stream is though! Even then, it is not perfect: it handles correctly the case gibberish is given through `std::cin`, but if you put more than two blocks separated by spaces the first two ones are used and the others aren't dealt with... As I said, proper and complete handling of input stream is though!
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2022_ © _CNRS 2016_ - _Inria 2018-2022_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ _This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_ _The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment