A better (hello) world? How would it be?
8. create a vector with the integers 1 20 and print a multiplication table
in several variations...
© Peter Sommerlad
Count the number of non-whitespace characters in standard input
© Peter Sommerlad
Count the number of non-whitespace characters in standard input
14
#include <iostream>
int main(){
size_t count{0}; char c{};
while (std::cin >> c) ++count; std::cout << count << "\n";
© Peter Sommerlad
Count the number of non-whitespace characters in standard input
14
#include <iostream>
int main(){
size_t count{0}; char c{};
while (std::cin >> c) ++count; std::cout << count << "\n";
}
#include <iostream>
#include <iterator>
int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; }
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
15 #include <iostream> int main() { size_t count { 0 }; while (std::cin.get()) ++count; std::cout << count << "\n"; }
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
15 #include <iostream> int main() { size_t count { 0 }; while (std::cin.get()) ++count; std::cout << count << "\n"; } #include <iostream> int main() { size_t count { 0 }; char c{}; while (std::cin.get(c)) ++count; std::cout << count << "\n"; }
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
15 #include <iostream> int main() { size_t count { 0 }; while (std::cin.get()) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; } #include <iostream> int main() { size_t count { 0 }; char c{}; while (std::cin.get(c)) ++count; std::cout << count << "\n"; }
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
15 #include <iostream> int main() { size_t count { 0 }; while (std::cin.get()) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; } #include <iostream> int main() { size_t count { 0 }; char c{}; while (std::cin.get(c)) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> int main(){
using iter = std::istreambuf_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; }
#include <iostream> int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
15 #include <iostream> int main() { size_t count { 0 }; while (std::cin.get()) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; } #include <iostream> int main() { size_t count { 0 }; char c{}; while (std::cin.get(c)) ++count; std::cout << count << "\n"; } #include <iostream> int main() { size_t count { 0 };
auto const eof=std::istream::traits_type::eof(); while (std::cin.get()!=eof) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> int main(){
using iter = std::istreambuf_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; }
#include <iostream>
int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
#include <iostream>
int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
16 #include <iostream> #include <string> int main(){ size_t count{0}; std::string s{};
while (std::cin >> s) ++count; std::cout << count << "\n";
#include <iostream>
int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
16
#include <iostream>
#include <iterator>
int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; } #include <iostream> #include <string> int main(){ size_t count{0}; std::string s{};
while (std::cin >> s) ++count; std::cout << count << "\n";
#include <iostream>
int main(){
size_t count{0}; char c;
while (std::cin >> c) ++count; std::cout << count << "\n";
}
© Peter Sommerlad
Count the number of bytes in standard input (aka wc -c)
16
#include <iostream>
#include <iterator>
int main(){
using iter = std::istream_iterator<char>;
std::cout << distance(iter{std::cin},iter{}) << "\n"; #include <iostream> #include <string> int main(){ size_t count{0}; std::string s{};
while (std::cin >> s) ++count; std::cout << count << "\n"; } #include <iostream> #include <iterator> #include <string> int main(){
using iter = std::istream_iterator<std::string>;
© Peter Sommerlad
Tally the number of occurrences of each (alphabetical) character in input
© Peter Sommerlad
Tally the number of occurrences of each (alphabetical) character in input
17 #include <iostream> #include <vector> #include <iterator> #include <cctype> #include <algorithm> using tally=std::vector<size_t>; tally collect(std::istream &in){
using iter=std::istream_iterator<char>;
tally v(256,0); // should be 2^bits in char
for_each(iter{in},iter{},[&v](char c){ ++v.at(c);}); return v;
}
void printTally(tally const &v, std::ostream &out){ for (auto i='A'; i<='Z'; ++i){
out<< i << " = " << v[i] << "\n"; auto li=char(std::tolower(i));
out<< li << " = " << v[li] << "\n"; }
© Peter Sommerlad
Tally the number of occurrences of each (alphabetical) character in input
using alias instead of typedef
parenthesis for initializer to disambiguate
{256,0} would create 2 element vector
Lambda with capture by reference
v needs to be changed narrowing conversion
needs type(value) tolower returns int
17 #include <iostream> #include <vector> #include <iterator> #include <cctype> #include <algorithm> using tally=std::vector<size_t>; tally collect(std::istream &in){
using iter=std::istream_iterator<char>;
tally v(256,0); // should be 2^bits in char
for_each(iter{in},iter{},[&v](char c){ ++v.at(c);}); return v;
}
void printTally(tally const &v, std::ostream &out){ for (auto i='A'; i<='Z'; ++i){
out<< i << " = " << v[i] << "\n"; auto li=char(std::tolower(i));
out<< li << " = " << v[li] << "\n"; } } int main(){ printTally(collect(std::cin),std::cout); }
© Peter Sommerlad
Tally the number of occurrences of each word in input
© Peter Sommerlad
Tally the number of occurrences of each word in input
18 #include <iostream> #include <map> #include <string> #include <iterator> #include <cctype> #include <algorithm> using tally=std::map<std::string,size_t>; tally collect(std::istream &in){
using iter=std::istream_iterator<std::string>; tally m;
for_each(iter{in},iter{},[&m](std::string s){ ++m[s];}); return m;
}
void printTally(tally const &m, std::ostream &out){ for (auto const & p : m){
out<< p.first << " = " << p.second << "\n"; }
}
int main(){
printTally(collect(std::cin),std::cout); }
© Peter Sommerlad
Tally the number of occurrences of each word in input
Lambda with capture by reference
m needs to be changed almost same code
range-based for best for looping maps
compare that to classic way need to know that map's
value type is a std::pair with first and second
no operator<< for std::pair or std::map available
could have used map for previous problem 18 #include <iostream> #include <map> #include <string> #include <iterator> #include <cctype> #include <algorithm> using tally=std::map<std::string,size_t>; tally collect(std::istream &in){
using iter=std::istream_iterator<std::string>; tally m;
for_each(iter{in},iter{},[&m](std::string s){ ++m[s];}); return m;
}
void printTally(tally const &m, std::ostream &out){ for (auto const & p : m){
out<< p.first << " = " << p.second << "\n"; }
© Peter Sommerlad
Tally the number of occurrences of each word in input (v2)
© Peter Sommerlad
Tally the number of occurrences of each word in input (v2)
19 #include <iostream> #include <string> #include <iterator> #include <cctype> #include <algorithm> #include <unordered_map> using counters=std::unordered_map<std::string,size_t>; counters collect(std::istream &in){
using iter=std::istream_iterator<std::string>; counters m;
for_each(iter{in},iter{},[&m](std::string s){ ++m[s];}); return m;
}
void printTally(counters const &m, std::ostream &out){ for (auto const & p:m){
out<< p.first << " = " << p.second << "\n"; }
© Peter Sommerlad
Tally the number of occurrences of each word in input (v2)
19 #include <iostream> #include <string> #include <iterator> #include <cctype> #include <algorithm> #include <unordered_map> using counters=std::unordered_map<std::string,size_t>; counters collect(std::istream &in){
using iter=std::istream_iterator<std::string>; counters m;
for_each(iter{in},iter{},[&m](std::string s){ ++m[s];}); return m;
}
void printTally(counters const &m, std::ostream &out){ for (auto const & p:m){
out<< p.first << " = " << p.second << "\n"; }
}
int main(){
printTally(collect(std::cin),std::cout); }
© Peter Sommerlad
Tally the number of occurrences of each word in input (v2)
unordered_map is hashing
not really suited here, better when read much more often
hashing only supported well for some standard types
missing std::hash<T> specializations
no standard support for combining hashes
DIY hashing by non-hash-
experts can lead to degraded performance
overfull and unbalanced
except for hashing strings, numbers or (smart) pointers
19 #include <iostream> #include <string> #include <iterator> #include <cctype> #include <algorithm> #include <unordered_map> using counters=std::unordered_map<std::string,size_t>; counters collect(std::istream &in){
using iter=std::istream_iterator<std::string>; counters m;
for_each(iter{in},iter{},[&m](std::string s){ ++m[s];}); return m;
}
void printTally(counters const &m, std::ostream &out){ for (auto const & p:m){
out<< p.first << " = " << p.second << "\n"; }
© Peter Sommerlad
sum up the numbers given in standard input
2011
It is time for writing some tests: Library:
© Peter Sommerlad
sum up the numbers given in standard input
2011 #include "cute.h" #include "ide_listener.h" #include "cute_runner.h" #include "sum.h" void testSumEmptyIsZero() { std::istringstream in{}; ASSERT_EQUAL(0.0,sum(in)); } void testSumOneEltIsElt(){ std::istringstream in{"2.5"}; ASSERT_EQUAL(2.5,sum(in)); } void testSumManyElts(){ std::istringstream in{"2.5 30 9.5"}; ASSERT_EQUAL(42.0,sum(in)); } void runSuite(){ cute::suite s; s.push_back(CUTE(testSumEmptyIsZero)); s.push_back(CUTE(testSumOneEltIsElt)); s.push_back(CUTE(testSumManyElts)); cute::ide_listener lis;
#ifndef SUM_H_
#define SUM_H_
#include <iosfwd>
double sum(std::istream& in);
#endif /* SUM_H_ */
#include "sum.h"
#include <istream>
#include <iterator>
#include <numeric>
double sum(std::istream& in) {
using it=std::istream_iterator<double>; return accumulate(it{in},it{},0.0);
}
It is time for writing some tests: Library:
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table
21
using veci = std::vector<int>;
veci create_ps(){
veci v(20,1); // v{20,1} wouldn't work! partial_sum(v.begin(),v.end(),v.begin()); return v;
}
void print_times_for(std::ostream& out, veci const& v) {
using vt=veci::value_type;
using oi=std::ostream_iterator<veci::value_type>; for(auto i:v){
transform(v.begin(), v.end(), oi{out,", "}, [i](vt x){return i*x;});
out << '\n'; }
}
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table
for vector<int> initializer with {20,1} would create a vector with these two elements
partial_sum adds up the 1s in the vector
range-based for loop can deduce type,
lambdas can not deduce
parameter type from argument (yet ?)
need to specify vt
21
using veci = std::vector<int>;
veci create_ps(){
veci v(20,1); // v{20,1} wouldn't work! partial_sum(v.begin(),v.end(),v.begin()); return v;
}
void print_times_for(std::ostream& out, veci const& v) {
using vt=veci::value_type;
using oi=std::ostream_iterator<veci::value_type>; for(auto i:v){
transform(v.begin(), v.end(), oi{out,", "}, [i](vt x){return i*x;});
out << '\n'; } } int main(){ print_times_for(std::cout,create_ps()); }
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table (2)
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table (2)
22
using veci = std::vector<int>;
veci create_iota(){
veci v(20); // v{20} wouldn't work! iota(v.begin(),v.end(),1);
return v; }
void print_times(std::ostream& out, veci const& v) { typedef veci::value_type vt;
typedef std::ostream_iterator<vt> oi; using std::placeholders::_1;
std::for_each(v.begin(),v.end(),[&out,v](vt y){ transform(v.begin(), v.end(), oi{out,", "}, bind(std::multiplies<vt>{},y,_1)); out << '\n'; }); } int main(){ print_times(std::cout,create_iota()); }
© Peter Sommerlad
create a vector with the integers 1..20 and print a multiplication table (2)
for vector<int> initializer with {20} would create a vector with just this element
iota takes the 1 and assigns the value and increments it for each step
its name comes from APL ι
there is no iota_n()
lambda capture by reference and by copy/value here
best to explicitly name captured variables
avoid dangling references!
bind is now part of std:: namespace
22
using veci = std::vector<int>;
veci create_iota(){
veci v(20); // v{20} wouldn't work! iota(v.begin(),v.end(),1);
return v; }
void print_times(std::ostream& out, veci const& v) { typedef veci::value_type vt;
typedef std::ostream_iterator<vt> oi; using std::placeholders::_1;
std::for_each(v.begin(),v.end(),[&out,v](vt y){ transform(v.begin(), v.end(), oi{out,", "}, bind(std::multiplies<vt>{},y,_1)); out << '\n';
}); }
© Peter Sommerlad
New stuff, we've seen so far
use using
for importing individual names (not new) and defining type aliases using alias definitions
"the better typedef"
new initializer syntax with braces
some disambiguation in case of std::vector<int> needed to access (size_t,T) ctor auto for variable type deduction
range-based for
in many cases algorithms still the better choice! use auto for element variable type deduction
Lambdas with capture by reference and parameter
© Peter Sommerlad
C++ 03 - Problem: Initialization
Plain Old Data - POD can be initialized like in C But that doesn't work with non-POD types
except std::tr1::array<T,n> all STL containers are NON-POD types.
Using Constructors can have interesting compiler messages when omitting parameters
instead of initializing a variable, you declare a function with no arguments who has not fallen into that trap?
struct B {}; B b();
declares a function called b returning a B and doesn't default-initialize a variable b
about 13 pages of the standard explain initializers! (plus references to other chapters)
however, one simple rule to understand it is sufficient in most applications
type variable { list of expressions for initialization };
works for almost all types in all contexts, even for initializing container elements
int i{}; double pi{3.14}; string s{"hello"}; vector<int> v{1,2,3,4,5,6}; direct initialization, copy initialization uses = between the variable and the {
constructing a value for a given type is:
type { list of expressions for initialization } int{}, double{5.5}, string{"hello world"}
That's it.
Choosing Parentheses:
() rounD Definition, Declaration -- {} Curly Construction, Creation
© Peter Sommerlad
C++11 provides "Uniform Initialization Syntax" using { }
© Peter Sommerlad
Examples for Using Uniform Initialization Syntax
Simple Variables
Vector Elements:
Constructor Initializer Lists and Member Initializers
26
! std::vector<std::string> v { "eins", "zwei", "drei" }; ! for (auto it=v.rbegin(); it != v.rend(); ++it){
! ! std::cout << "item : "<< *it << std::endl; ! }
struct A {
! A(int i):val{i}{} ! int val;
int i{}; // zero
std::string hello{"Hello World"};
© Peter Sommerlad
Caveat - Constructor Overloads and initializer lists
for a class with overloaded constructors and one overload is with initializer_list<T> using one of the other constructors that also takes parameters of type T might
require using "traditional" parenthesis syntax.
use uniform initializer syntax, but be prepared to use "old" parenthesis syntax in case to access non-initializer list constructor overload if both would match.
problem with member-initializers (no viable syntax, must use constructor's initialization)
27
std::vector<int> v(10u); // vector(size_t n, T t=T{}) // 10 elements
std::vector<int> v{10u,2}; // vector with two int elements // because initializer_list<int> matches parameters
std::vector<std::string> v{10u}; // vector with 10 string
// because intializer_list<std::string> doesn't match {10u} // fallback to regular ctor overload
© Peter Sommerlad
C++11 Example for Using initializer lists in own Classes
To use arbitrary length lists of values of the same type for your constructors the standard provides std::intializer_list<T> as a parameter type.
Do not use std::initializer_list<T> for anything else. Only if you design your own "container-like" types.
advanced stuff, beyond this talk --> you need your "C++11 pilot license" first!
28
template<typename T> struct use_vector_memberT {
use_vector_memberT(std::initializer_list<T> l) :v{l}{}
void print(std::ostream & out){ for(auto x: v){
out << "value = " << x << std::endl; }
© Peter Sommerlad
C++11 Example for Using initializer lists in own Classes
To use arbitrary length lists of values of the same type for your constructors the standard provides std::intializer_list<T> as a parameter type.
Do not use std::initializer_list<T> for anything else. Only if you design your own "container-like" types.
advanced stuff, beyond this talk --> you need your "C++11 pilot license" first!
28
C++
HSR
template<typename T> struct use_vector_memberT {
use_vector_memberT(std::initializer_list<T> l) :v{l}{}
void print(std::ostream & out){ for(auto x: v){
out << "value = " << x << std::endl; }
}
private:
std::vector<T> v; };
© Peter Sommerlad
C++11 Example for Using initializer lists in own Classes
To use arbitrary length lists of values of the same type for your constructors the standard provides std::intializer_list<T> as a parameter type.
Do not use std::initializer_list<T> for anything else. Only if you design your own "container-like" types.
advanced stuff, beyond this talk --> you need your "C++11 pilot license" first!
28
template<typename T> struct use_vector_memberT {
use_vector_memberT(std::initializer_list<T> l) :v{l}{}
void print(std::ostream & out){ for(auto x: v){
out << "value = " << x << std::endl; }
© Peter Sommerlad
C++ 03 - Problem: Complicated Return Types for Variables
Some library functions return complicated types, especially when using templates some help through typedefs or traits, but still cumbersome
std::vector<std::string>::const_reverse_iterator it=v.rbegin(); std::iterator_traits<iterator_type>::value_type v = *it;
With some library functions the return type is even "unspecified" You are not intended to keep track of it, e.g., bind1st(), tr1::bind() how can you save its return value in a variable
well, it works in a template context, but not in general
for initializing heap objects, one even needs to repeat the type, like in Java there exists an alternative way in C++11: make_shared<type>(...)
auto is a real life saver now
auto it=find(v.rbegin(),v.rend(),42);
auto first= *aMap.begin(); // std::pair<key,value> auto can be combined with (const) reference or pointer
auto i=42; auto &iref=i; // i is of type int, iref of type int& caveat: cannot use easily uniform initializer syntax without specifying the type
auto i{42}; -> i is of type std::intializer_list<int>
Rule of Thumb:
Define (local) variables with auto and determine their type through their initializer especially handy within template code!
© Peter Sommerlad
C++11 auto provides Automatic Type Deduction for Initialized Variables
© Peter Sommerlad
auto - Examples
iterator variable, element from iterator access
late function return type
late function return type (deduction from expression with decltype() )
31
for (vector<string>::reverse_iterator it=v.rbegin(); it != v.rend(); ++it){
! ! vector<string>::value_type elt = *it; ! ! cout << "item : "<< elt << endl;
© Peter Sommerlad
auto - Examples
iterator variable, element from iterator access
late function return type
late function return type (deduction from expression with decltype() )
31
for (auto it=v.rbegin(); it != v.rend(); ++it){ ! ! auto elt = *it;
! ! cout << "item : "<< elt << endl; }
© Peter Sommerlad