• No results found

create a vector with the integers 1 20 and print a multiplication table

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

auto - Examples

Related documents