22
Modern C++ Modern C++ Range-Based For Loops

Modern C++ Range Based for Loops

Embed Size (px)

DESCRIPTION

Initial draft of Modern C++: Range Based For LoopsMay contain bad grammer mistacks, ba df ormatting, and corrupted informati@#$23segfault

Citation preview

Modern C++Modern C++

Range-Based For Loops

What is a range?What is a range?

● essentially, a range is a series of elements between a beginning and an endessentially, a range is a series of elements between a beginning and an end● in STL terminology, begin and end are represented as iteratorsin STL terminology, begin and end are represented as iterators [1][1]

● forward-iterating over the range of a STL container means starting at begin forward-iterating over the range of a STL container means starting at begin and stepping toward end one element at a timeand stepping toward end one element at a time

● for-loops now have an alternate syntax for handling ranges such as those for-loops now have an alternate syntax for handling ranges such as those found in forward-iterable STL containersfound in forward-iterable STL containers[1] for a formal description, see § 24.2.1[1] for a formal description, see § 24.2.1

Conventional ApproachConventional Approach

● syntax: for (init-statement; condition [optional]; expression [optional])

● When dealing with ranges, conventional for looping has a few quirks

– they are often overly verbose, especially when dealing with templates

– it is possible to accidently bring about undefined behavior by stepping out of range

– if condition is not a constant expression or otherwise cached, performance may take a hit

– syntatical differences may be required for user-defined data types

1  | #include <iostream> // for std::cout, std::endl, std::ostream2  | #include <vector> // for std::vector3  |4  | template<typename T, typename U>5  | struct Pair6  | {7  | T t;8  | U u;9  | };10 |11 | template<typename T, typename U>12 | std::ostream& operator<<(std::ostream& stream, const Pair<T, U>& pair)13 | {14 | stream << pair.t << pair.u;15 | return stream;16 | }17 |18 | int main()19 | {20 | std::vector<Pair<int, int>> vector1, vector2 = {{1, 1}};21 | for(std::vector<Pair<int, int>>::iterator iter = vector1.begin(); iter != vector2.end(); ++iter)22 | {23 | std::cout << *iter << std::endl;24 | }25 | }26 |27 |28 |29 |30 |31 |32 |33 |34 |35 |36 |37 | // Historical Challenge38 |39 | // In addition to the undefined behavior, this source contains two artifacts that will not compile under C++0340 | // Can you find them?41 |______________________________________________________________________________________________________________________________________________________________> clang++ ­std=c++11 ./range_based_for_loops/conventional.cpp ­o ./test_build/range_based_for_loops/conventional> ./test_build/range_based_for_loops/conventional> Segmentation fault

1  | #include <iostream> // for std::cout, std::endl, std::ostream2  | #include <vector> // for std::vector3  |4  | template<typename T, typename U>5  | struct Pair6  | {7  | T t;8  | U u;9  | };10 |11 | template<typename T, typename U>12 | std::ostream& operator<<(std::ostream& stream, const Pair<T, U>& pair)13 | {14 | stream << pair.t << pair.u;15 | return stream;16 | }17 |18 | int main()19 | {20 | std::vector<Pair<int, int>> vector1, vector2 = {{1, 1}};21 | for(std::vector<Pair<int, int>>::iterator iter = vector1.begin(); iter != vector2.end(); ++iter)22 | {23 | std::cout << *iter << std::endl;24 | }25 | }26 |27 |28 |29 |30 |31 |32 |33 |34 |35 |36 |37 | // Historical Challenge38 |39 | // In addition to the undefined behavior, this source contains two artifacts that will not compile under C++0340 | // Can you find them?41 |______________________________________________________________________________________________________________________________________________________________> clang++ ­std=c++11 ./range_based_for_loops/conventional.cpp ­o ./test_build/range_based_for_loops/conventional> ./test_build/range_based_for_loops/conventional> Segmentation fault

New Syntax for RangesNew Syntax for Ranges

● Syntax: Syntax: for(element : range-object) statement for(element : range-object) statement● element element is a variable that holds an element in the rangeis a variable that holds an element in the range

– elementelement may be may be cv-qualifiedcv-qualified[1][1]

– element element may also be may also be autoauto[2][2]

● range-objectrange-object is an object that satisfies range-based requirements is an object that satisfies range-based requirements[3][3]

● statementstatement is simply the block of code that makes up the body of the loop is simply the block of code that makes up the body of the loop

[1] [1] constconst or or volatilevolatile (§ 7.1.6.1) (§ 7.1.6.1)

[2] compiler deduced type (§ 7.1.6.4)[2] compiler deduced type (§ 7.1.6.4)

[3] that is, providing [3] that is, providing beginbegin and and endend facilities returning iterators that provide operatoroperator++, ++, operatoroperator*, and *, and operator!= operator!= (§ 6.5.4)(§ 6.5.4)

1#include <iostream> // for std::cout, std::endl, std::ostream2#include <vector> // for std::vector34  | template<typename T, typename U>5  | struct Pair6  | {7  | T t;8  | U u;9  | };10 |11 | template<typename T, typename U>12 | std::ostream& operator<<(std::ostream& stream, const Pair<T, U>& pair)13 | {14 | stream << pair.t << pair.u;15 | return stream;16 | }17 |18 | int main()19 | {20 | std::vector<Pair<int, int>> vector;21 |22 | // Notice that this syntax:23 | // 1) is much shorter24 | // 2) makes it impossible to accidently step out of range25 | // 3) makes no temporary copies of end()26 | // 4) handles all ranges with a uniform syntax27 | for(const Pair<int, int>& pair : vector)28 | {29 | std::cout << pair << std::endl;30 | }31 | }32

1#include <iostream> // for std::cout, std::endl, std::ostream2#include <vector> // for std::vector34  | template<typename T, typename U>5  | struct Pair6  | {7  | T t;8  | U u;9  | };10 |11 | template<typename T, typename U>12 | std::ostream& operator<<(std::ostream& stream, const Pair<T, U>& pair)13 | {14 | stream << pair.t << pair.u;15 | return stream;16 | }17 |18 | int main()19 | {20 | std::vector<Pair<int, int>> vector;21 |22 | // Notice that this syntax:23 | // 1) is much shorter24 | // 2) makes it impossible to accidently step out of range25 | // 3) makes no temporary copies of end()26 | // 4) handles all ranges with a uniform syntax27 | for(const Pair<int, int>& pair : vector)28 | {29 | std::cout << pair << std::endl;30 | }31 | }32

Under the HoodUnder the Hood

● how the new syntax operates internally is conceptually simplehow the new syntax operates internally is conceptually simple [1][1]

● essentially, there are only a few steps involvedessentially, there are only a few steps involved● the first step involves the compiler figuring which functions to use to the first step involves the compiler figuring which functions to use to

get iterators to get iterators to beginbegin and and endend● The second step is to apply a subtle syntatic precaution if an The second step is to apply a subtle syntatic precaution if an

expression is provided as expression is provided as range-objectrange-object● the third step involves a simple bit of synthetic code generationthe third step involves a simple bit of synthetic code generation

[1] – I do not believe that compiler implementations are explicitly required to follow this method, but it is how the standard describes it nevertheless.[1] – I do not believe that compiler implementations are explicitly required to follow this method, but it is how the standard describes it nevertheless.

Under the Hood (continued)Under the Hood (continued)

● Step 1 – figuring out which functions to use for Step 1 – figuring out which functions to use for beginbegin and and endend● If If range-objectrange-object is an array type, then is an array type, then beginbegin is simply a pointer to its is simply a pointer to its

first element and first element and endend is a pointer to one past its last element is a pointer to one past its last element● If If range-objectrange-object is a class type, then there are three possibilities is a class type, then there are three possibilities

– 1) Does the class type provide member methods 1) Does the class type provide member methods beginbegin and and endend??● Yes? Use themYes? Use them

– 2) Do there exist namespace-scope functions 2) Do there exist namespace-scope functions begin begin and and endend that take an that take an object of type object of type range-objectrange-object??

● Yes? Use themYes? Use them

– 3) Do there exist template specializations of 3) Do there exist template specializations of std::beginstd::begin and and std::endstd::end for an for an object of type object of type range-objectrange-object??

● Yes? Use themYes? Use them

– If no functions are found, then the program is ill-formedIf no functions are found, then the program is ill-formed

Under the Hood (continued)Under the Hood (continued)

● Step 2 – Step 2 – apply a syntatic precaution if apply a syntatic precaution if range-object range-object is an is an expressionexpression● In such an event, In such an event, range-objectrange-object is wrapped by a pair of parenthesis is wrapped by a pair of parenthesis

– This prevents top-level comma operators from being interpreted incorrectly, This prevents top-level comma operators from being interpreted incorrectly, thus forming an ambiguitythus forming an ambiguity

– Consider the following: Consider the following: int array[] = {1, 2, 3, 4, 5};int array[] = {1, 2, 3, 4, 5};

for(int x : ++x[0], array);for(int x : ++x[0], array);

● the (legal, but a bit obscure) expression the (legal, but a bit obscure) expression ++x[0], array++x[0], array would become would become (++x[0], array)(++x[0], array)

● Step 2 is skipped if Step 2 is skipped if range-objectrange-object is a braced initializer list is a braced initializer list

Under the Hood (continued)Under the Hood (continued)for(element : range-object) statementfor(element : range-object) statement

● Step 3 – Synthetic Code GenerationStep 3 – Synthetic Code Generation● Given the previous steps, let us generalize the strict rules a bitGiven the previous steps, let us generalize the strict rules a bit

– let the functions for getting let the functions for getting beginbegin and and end end be be begin-exprbegin-expr and and end-exprend-expr, respectively, respectively

– let let range-objectrange-object (be it expression or braced initializer list) be (be it expression or braced initializer list) be range-initrange-init

● Now the compiler rewrites the loop as follows:Now the compiler rewrites the loop as follows:

range-object-type __range&& = range-init;range-object-type __range&& = range-init;

for(range-object-type-iterator __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin)for(range-object-type-iterator __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin)

{{

element-type element = *__begin;element-type element = *__begin;

statementstatement

}}

– Essentially, the compiler has simply taken the new syntax and converted it to the oldEssentially, the compiler has simply taken the new syntax and converted it to the old

Under the Hood (continued)Under the Hood (continued)examplesexamples

1  |2  |3  | // Example 14  | std::vector<int> vector {1, 2, 3, 4};5  | auto&& __range = (vector);6  | for(auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin)7  | {8  | auto i = *__begin;9  | std::cout << i << std::endl;10 | }11 |12 | // Example 213 | int array[] = {1, 2, 3, 4};14 | auto&& __range = (array);15 | for(auto __begin = __range, __end = __range + (sizeof(__range) / sizeof(int)); __begin != __end; ++__begin)16 | {17 | auto i = *__begin;18 | std::cout << i << std::endl;19 | }20 |21 | // Example 322 | auto&& __range = {1, 2, 3, 4};23 | for(auto __begin = __range.begin(), __end == __range.end(); __begin != __end; ++__begin)24 | {25 | auto i = *__begin;26 | std::cout << i << std::endl;27 | }28 |

1  |2  |3  | // Example 14  | std::vector<int> vector {1, 2, 3, 4};5  | auto&& __range = (vector);6  | for(auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin)7  | {8  | auto i = *__begin;9  | std::cout << i << std::endl;10 | }11 |12 | // Example 213 | int array[] = {1, 2, 3, 4};14 | auto&& __range = (array);15 | for(auto __begin = __range, __end = __range + (sizeof(__range) / sizeof(int)); __begin != __end; ++__begin)16 | {17 | auto i = *__begin;18 | std::cout << i << std::endl;19 | }20 |21 | // Example 322 | auto&& __range = {1, 2, 3, 4};23 | for(auto __begin = __range.begin(), __end == __range.end(); __begin != __end; ++__begin)24 | {25 | auto i = *__begin;26 | std::cout << i << std::endl;27 | }28 |

1  |2  |3  | // Example 14  | std::vector<int> vector {1, 2, 3, 4};5  | for(int i : vector)6  | {7  | std::cout << i << std::endl;8  | }9  |10 |11 |12 |13 | // Example 214 | int array[] = {1, 2, 3, 4};15 | for(int i : array)16 | {17 | std::cout << i << std::endl;18 | }19 |20 |21 |22 | // Example 323 | for(int i : {1, 2, 3, 4})24 | {25 | std::cout << i << std::endl;26 | }27 |

1  |2  |3  | // Example 14  | std::vector<int> vector {1, 2, 3, 4};5  | for(int i : vector)6  | {7  | std::cout << i << std::endl;8  | }9  |10 |11 |12 |13 | // Example 214 | int array[] = {1, 2, 3, 4};15 | for(int i : array)16 | {17 | std::cout << i << std::endl;18 | }19 |20 |21 |22 | // Example 323 | for(int i : {1, 2, 3, 4})24 | {25 | std::cout << i << std::endl;26 | }27 |

Programmer Input Synthetic Output

Extensibility: User Defined TypesExtensibility: User Defined Types

● making user-defined types compatible with range-based formaking user-defined types compatible with range-based for syntax requires meeting the minimum requirements of two interfaces

● range Interface– must provide at least one of the following

● member functions begin and end● free functions begin and end● template specializations of std::begin and std::end

– the type returned must meet the requirements of the second interface

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)

● iterator interfaceiterator interface– iterators are returned from the iterators are returned from the beginbegin and and endend methods of ranges methods of ranges– iterator types must provide the following operators with either members or iterator types must provide the following operators with either members or

free-functionsfree-functions● operator++()operator++()● operator*()operator*()● operator!=()operator!=()

– note – operator++() refers to the note – operator++() refers to the prefixprefix operator operator– note – operator*() may be overridden for const-correctness, and is always best note – operator*() may be overridden for const-correctness, and is always best

practice to do so.practice to do so.

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)

● a quick note on 'free functions'a quick note on 'free functions'– free functions allow the addition of new functionality without modifying a classfree functions allow the addition of new functionality without modifying a class– can be particularly useful when unable to modify a class (IE library class)can be particularly useful when unable to modify a class (IE library class)– generally act to loosen API couplinggenerally act to loosen API coupling– Herb Sutter has published an in-depth article on free functions Herb Sutter has published an in-depth article on free functions [1][1]

[1] http://www.gotw.ca/publications/mill02.htm[1] http://www.gotw.ca/publications/mill02.htm

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)Iterator class with member functionsIterator class with member functions

1  | #ifndef ITERATOR_HPP2  | #define ITERATOR_HPP3  |4  | #include <cstdint> // for std::size_t5  |6  | template<tyypename T>7  | class Iterator8  | {9  | T* data;10 | std::size_t position;11 |12 |   public:13 |14 | Iterator(T* data, std::size_t position) :15 | data(data),16 | position(position) { }17 |18 | /// Compares this iterator to another returning true if they are not equal, otherwise false19 | bool operator!=(const Iterator& other) const20 | {21 | return this­>position != other.position;22 | }23 |24 | /// Dereferences this iterator to a reference25 | T& operator*()26 | {27 | return *(data + position);28 | }29 |30 | /// Dereferences this iterator to a const reference31 | const T& operator*() const32 | {33 | return *(data + position);34 | }35 |36 | /// Increments this iterator to point to the next element37 | const Iterator& operator++()38 | {39 | ++position;40 | return *this;41 | }42 | };43 |44 | #endif // ITERATOR_HPP45 |

1  | #ifndef ITERATOR_HPP2  | #define ITERATOR_HPP3  |4  | #include <cstdint> // for std::size_t5  |6  | template<tyypename T>7  | class Iterator8  | {9  | T* data;10 | std::size_t position;11 |12 |   public:13 |14 | Iterator(T* data, std::size_t position) :15 | data(data),16 | position(position) { }17 |18 | /// Compares this iterator to another returning true if they are not equal, otherwise false19 | bool operator!=(const Iterator& other) const20 | {21 | return this­>position != other.position;22 | }23 |24 | /// Dereferences this iterator to a reference25 | T& operator*()26 | {27 | return *(data + position);28 | }29 |30 | /// Dereferences this iterator to a const reference31 | const T& operator*() const32 | {33 | return *(data + position);34 | }35 |36 | /// Increments this iterator to point to the next element37 | const Iterator& operator++()38 | {39 | ++position;40 | return *this;41 | }42 | };43 |44 | #endif // ITERATOR_HPP45 |

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)Iterator class with free functionsIterator class with free functions

1  | #ifndef ITERATOR_HPP2  | #define ITERATOR_HPP3  |4  | #include <cstdint> // for std::size_t5  |6  | // Forward Declare to use with our free function declarations7  | template<typename T> class Iterator;8  |9  | /// Compares this iterator to another returning true if they are not equal, otherwise false10 | template<typename T> bool operator!=(const Iterator<T>& lhs, const Iterator<T>& rhs);11 |12 | /// Dereferences this iterator to a reference13 | template<typename T> T& operator*(Iterator<T>& iter);14 | /// Dereferences this iterator to a const reference15 | template<typename T> const T& operator*(const Iterator<T>& iter);16 |17 | /// Increments this iterator to point to the next element18 | template<typename T> Iterator<T>& operator++(Iterator<T>& iter);19 |20 | template<typename T>21 | class Iterator22 | {23 | // Specialized friend declarations24 | friend bool operator!=<>(const Iterator<T>&, const Iterator<T>&);25 | friend T& operator*<>(Iterator<T>&);26 | friend const T& operator*<>(const Iterator<T>&);27 | friend Iterator<T>& operator++<>(Iterator<T>&);28 |29 | T* data;30 | std::size_t position;31 |32 |   public:33 |34 | Iterator(T* data, std::size_t position) : data(data), position(position) { }35 | };36 | /// Provide definitions for our free functions37 | template<typename T>38 | bool operator!=(const Iterator<T>& lhs, const Iterator<T>& rhs)39 | {40 | return lhs.position != rhs.position;41 | }42 |43 | template<typename T>44 | T& operator*(Iterator<T>& iter)45 | {46 | return *(iter.data + iter.position);47 | }48 |49 | template<typename T>50 | const T& operator*(const Iterator<T>& iter)51 | {52 | return *(iter.data + iter.position);53 | }54 |55 | template<typename T>56 | Iterator<T>& operator++(Iterator<T>& iter)57 | {58 | ++iter.position;59 | return iter;60 | }61 |62 | #endif // ITERATOR_HPP63 |

1  | #ifndef ITERATOR_HPP2  | #define ITERATOR_HPP3  |4  | #include <cstdint> // for std::size_t5  |6  | // Forward Declare to use with our free function declarations7  | template<typename T> class Iterator;8  |9  | /// Compares this iterator to another returning true if they are not equal, otherwise false10 | template<typename T> bool operator!=(const Iterator<T>& lhs, const Iterator<T>& rhs);11 |12 | /// Dereferences this iterator to a reference13 | template<typename T> T& operator*(Iterator<T>& iter);14 | /// Dereferences this iterator to a const reference15 | template<typename T> const T& operator*(const Iterator<T>& iter);16 |17 | /// Increments this iterator to point to the next element18 | template<typename T> Iterator<T>& operator++(Iterator<T>& iter);19 |20 | template<typename T>21 | class Iterator22 | {23 | // Specialized friend declarations24 | friend bool operator!=<>(const Iterator<T>&, const Iterator<T>&);25 | friend T& operator*<>(Iterator<T>&);26 | friend const T& operator*<>(const Iterator<T>&);27 | friend Iterator<T>& operator++<>(Iterator<T>&);28 |29 | T* data;30 | std::size_t position;31 |32 |   public:33 |34 | Iterator(T* data, std::size_t position) : data(data), position(position) { }35 | };36 | /// Provide definitions for our free functions37 | template<typename T>38 | bool operator!=(const Iterator<T>& lhs, const Iterator<T>& rhs)39 | {40 | return lhs.position != rhs.position;41 | }42 |43 | template<typename T>44 | T& operator*(Iterator<T>& iter)45 | {46 | return *(iter.data + iter.position);47 | }48 |49 | template<typename T>50 | const T& operator*(const Iterator<T>& iter)51 | {52 | return *(iter.data + iter.position);53 | }54 |55 | template<typename T>56 | Iterator<T>& operator++(Iterator<T>& iter)57 | {58 | ++iter.position;59 | return iter;60 | }61 |62 | #endif // ITERATOR_HPP63 |

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)Container class with member functionsContainer class with member functions

1  | #ifndef CONTAINER_HPP2  | #define CONTAINER_HPP3  |4  | #include <cstdint>              // for std::size_t5  | #include "iterator_members.hpp" // for Iterator (can interchange "iterator_free.hpp" as well!)6  |7  | template<typename T, std::size_t N, typename Iter = Iterator<T>>8  | class Container9  | {10 | T elements[N];11 |12 |   public:13 |14 | typedef Iter iterator;15 | typedef const Iter const_iterator;16 |17 | /// begin facilities18 | iterator begin()19 | {20 | return iterator(elements, 0);21 | }22 |23 | const_iterator begin() const24 | {25 | return const_iterator(elements, 0);26 | }27 |28 | /// end facilities29 | iterator end()30 | {31 | return iterator(elements, N);32 | }33 |34 | const_iterator end() const35 | {36 | return const_iterator(elements, N);37 | }38 |39 | /// random access40 | T& operator[](std::size_t index)41 | {42 | return elements[index];43 | }44 |45 | const T& operator[](std::size_t index) const46 | {47 | return elements[index];48 | }49 | };50 |51 | #endif // CONTAINER_HPP52 |

1  | #ifndef CONTAINER_HPP2  | #define CONTAINER_HPP3  |4  | #include <cstdint>              // for std::size_t5  | #include "iterator_members.hpp" // for Iterator (can interchange "iterator_free.hpp" as well!)6  |7  | template<typename T, std::size_t N, typename Iter = Iterator<T>>8  | class Container9  | {10 | T elements[N];11 |12 |   public:13 |14 | typedef Iter iterator;15 | typedef const Iter const_iterator;16 |17 | /// begin facilities18 | iterator begin()19 | {20 | return iterator(elements, 0);21 | }22 |23 | const_iterator begin() const24 | {25 | return const_iterator(elements, 0);26 | }27 |28 | /// end facilities29 | iterator end()30 | {31 | return iterator(elements, N);32 | }33 |34 | const_iterator end() const35 | {36 | return const_iterator(elements, N);37 | }38 |39 | /// random access40 | T& operator[](std::size_t index)41 | {42 | return elements[index];43 | }44 |45 | const T& operator[](std::size_t index) const46 | {47 | return elements[index];48 | }49 | };50 |51 | #endif // CONTAINER_HPP52 |

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)Container class with free functionsContainer class with free functions

1  | #ifndef CONTAINER_HPP2  | #define CONTAINER_HPP3  |4  | #include <cstdint> // for std::size_t5  | #include "iterator_free.hpp" // for Iterator (can interchange "iterator_members.hpp" as well!))6  |7  | template<typename T, std::size_t N, typename Iter = Iterator<T>>8  | class Container9  | {10 | T elements[N];11 |12 |  public:13 |14 | typedef Iter iterator;15 | typedef const Iter const_iterator;16 |17 | T& operator[](std::size_t index)18 | {19 | return elements[index];20 | }21 |22 | const T& operator[](std::size_t index) const23 | {24 | return elements[index];25 | }26 |27 | };28 |29 | template<typename T, std::size_t N, typename Iter = Iterator<T>>30 | typename Container<T, N, Iter>::iterator begin(Container<T, N, Iter>& arr)31 | {32 | return typename Container<T, N, Iter>::iterator(&arr[0], 0);33 | }34 |35 | template<typename T, std::size_t N, template Iter = Iterator<T>>36 | typename Container<T, N, Iter>::iterator end(Container<T, N, Iter>& arr)37 | {38 | return typename Container<T, N, Iter>::iterator(&arr[0], N);39 | }40 |41 | template<template T, std::size_t N, typename Iter = Iterator<T>>42 | typename Container<T, N, Iter>::const_iterator begin(const Container<T, N, Iter>& arr)43 | {44 | return typename Container<T, N, Iter>::const_iterator(&arr[0], 0);45 | }46 |47 | template<typename T, std::size_t N, template Iter = Iterator<T>>48 | typename Container<T, N, Iter>::const_iterator end(const Container<T, N, Iter>& arr)49 | {50 | return typename Container<T, N, Iter>::const_iterator(&arr[0], N);51 | }52 |53 | #endif // CONTAINER_HPP54 |

1  | #ifndef CONTAINER_HPP2  | #define CONTAINER_HPP3  |4  | #include <cstdint> // for std::size_t5  | #include "iterator_free.hpp" // for Iterator (can interchange "iterator_members.hpp" as well!))6  |7  | template<typename T, std::size_t N, typename Iter = Iterator<T>>8  | class Container9  | {10 | T elements[N];11 |12 |  public:13 |14 | typedef Iter iterator;15 | typedef const Iter const_iterator;16 |17 | T& operator[](std::size_t index)18 | {19 | return elements[index];20 | }21 |22 | const T& operator[](std::size_t index) const23 | {24 | return elements[index];25 | }26 |27 | };28 |29 | template<typename T, std::size_t N, typename Iter = Iterator<T>>30 | typename Container<T, N, Iter>::iterator begin(Container<T, N, Iter>& arr)31 | {32 | return typename Container<T, N, Iter>::iterator(&arr[0], 0);33 | }34 |35 | template<typename T, std::size_t N, template Iter = Iterator<T>>36 | typename Container<T, N, Iter>::iterator end(Container<T, N, Iter>& arr)37 | {38 | return typename Container<T, N, Iter>::iterator(&arr[0], N);39 | }40 |41 | template<template T, std::size_t N, typename Iter = Iterator<T>>42 | typename Container<T, N, Iter>::const_iterator begin(const Container<T, N, Iter>& arr)43 | {44 | return typename Container<T, N, Iter>::const_iterator(&arr[0], 0);45 | }46 |47 | template<typename T, std::size_t N, template Iter = Iterator<T>>48 | typename Container<T, N, Iter>::const_iterator end(const Container<T, N, Iter>& arr)49 | {50 | return typename Container<T, N, Iter>::const_iterator(&arr[0], N);51 | }52 |53 | #endif // CONTAINER_HPP54 |

Extensibility: User Defined Types (continued)Extensibility: User Defined Types (continued)Using our ContainerUsing our Container

1  | #include <iostream> // for std::cout2  |3  | // uncomment to use a free function implementation4  | //#define USE_FREE_FUNCTIONS5  |6  | #ifdef USE_FREE_FUNCTIONS7  | #include "container_free.hpp" // for Container (implemented with free functions)8  | #else9  | #include "container_members.hpp" // for Container (implemented with member functions)10 | #endif11 |12 | int main()13 | {14 | Container<int, 4> integers;15 | int counter = 0;16 | std::cout << "Uninitialized Values\n";17 | for(int& i : integers)18 | {19 | std::cout << i << "\n";20 | i = counter++;21 | }22 | std::cout << "\nInitialized Values\n";23 |24 | for(int i : integers)25 | {26 | std::cout << i << "\n";27 | }28 | std::cout.flush();29 | }30 |

1  | #include <iostream> // for std::cout2  |3  | // uncomment to use a free function implementation4  | //#define USE_FREE_FUNCTIONS5  |6  | #ifdef USE_FREE_FUNCTIONS7  | #include "container_free.hpp" // for Container (implemented with free functions)8  | #else9  | #include "container_members.hpp" // for Container (implemented with member functions)10 | #endif11 |12 | int main()13 | {14 | Container<int, 4> integers;15 | int counter = 0;16 | std::cout << "Uninitialized Values\n";17 | for(int& i : integers)18 | {19 | std::cout << i << "\n";20 | i = counter++;21 | }22 | std::cout << "\nInitialized Values\n";23 |24 | for(int i : integers)25 | {26 | std::cout << i << "\n";27 | }28 | std::cout.flush();29 | }30 |

Extensibility: Reverse IterationExtensibility: Reverse Iteration

● reverse iteration with the new syntax is also possiblereverse iteration with the new syntax is also possible● essentially, all that is required is a handful of helper function templates essentially, all that is required is a handful of helper function templates

and a delegate class to provide reverse-iterators from its and a delegate class to provide reverse-iterators from its beginbegin and and endend methods methods

● this also means, of course, that the type has to be this also means, of course, that the type has to be reverse-iterablereverse-iterable● many (if not all) of the helpers are expected to be built into c++14many (if not all) of the helpers are expected to be built into c++14

Extensibility: Reverse Iteration (continued)Extensibility: Reverse Iteration (continued)1  | #include <iterator>2  |3  | namespace detail4  | {5  | template<typename Iterable> auto rbegin(Iterable& iterable) ­> decltype(iterable.rbegin())6  | {7  | return iterable.rbegin();8  | }9  |10 | template<typename Iterable> auto rbegin(const Iterable& iterable) ­> decltype(iterable.rbegin())11 | {12 | return iterable.rbegin();13 | }14 |15 | template<typename T, std::size_t N> std::reverse_iterator<T*> rbegin(T(&a)[N])16 | {17 | return std::reverse_iterator<T*>(std::end(a));18 | }19 |20 | template<typename Iterable> auto rend(Iterable& iterable) ­> decltype(iterable.rend())21 | {22 | return iterable.rend();23 | }24 |25 | template<typename Iterable> auto rend(const Iterable& iterable) ­> decltype(iterable.rend())26 | {27 | return iterable.rend();28 | }29 |30 | template<typename T, std::size_t N > std::reverse_iterator<T*> rend(T(&a)[N])31 | {32 | return std::reverse_iterator<T*>(std::begin(a));33 | }34 |35 | template<typename Iterable> struct reverse36 | {37 | Iterable& range;38 | reverse(Iterable& r) : range(r) { }39 | auto begin() ­> decltype(rbegin(range)) { return rbegin(range); }40 | auto end() ­> decltype(rend(range)) { return rend(range); }41 | };42 | }43 |44 | template<typename Iterable> detail::reverse<Iterable> reverse(Iterable& r)45 | {46 | return detail::reverse<Iterable>(r);47 | }48 |49 | #include <iostream>50 |51 | int main()52 | {53 | int x[] {1, 2, 3, 4, 5, 6, 7, 8, 9};54 | for(int i : x)55 | {56 | std::cout << i << ' ';57 | }58 | std::cout << std::endl;59 | for(int i : reverse(x))60 | {61 | std::cout << i << ' ';62 | }63 | std::cout << std::endl;64 | }65 |

1  | #include <iterator>2  |3  | namespace detail4  | {5  | template<typename Iterable> auto rbegin(Iterable& iterable) ­> decltype(iterable.rbegin())6  | {7  | return iterable.rbegin();8  | }9  |10 | template<typename Iterable> auto rbegin(const Iterable& iterable) ­> decltype(iterable.rbegin())11 | {12 | return iterable.rbegin();13 | }14 |15 | template<typename T, std::size_t N> std::reverse_iterator<T*> rbegin(T(&a)[N])16 | {17 | return std::reverse_iterator<T*>(std::end(a));18 | }19 |20 | template<typename Iterable> auto rend(Iterable& iterable) ­> decltype(iterable.rend())21 | {22 | return iterable.rend();23 | }24 |25 | template<typename Iterable> auto rend(const Iterable& iterable) ­> decltype(iterable.rend())26 | {27 | return iterable.rend();28 | }29 |30 | template<typename T, std::size_t N > std::reverse_iterator<T*> rend(T(&a)[N])31 | {32 | return std::reverse_iterator<T*>(std::begin(a));33 | }34 |35 | template<typename Iterable> struct reverse36 | {37 | Iterable& range;38 | reverse(Iterable& r) : range(r) { }39 | auto begin() ­> decltype(rbegin(range)) { return rbegin(range); }40 | auto end() ­> decltype(rend(range)) { return rend(range); }41 | };42 | }43 |44 | template<typename Iterable> detail::reverse<Iterable> reverse(Iterable& r)45 | {46 | return detail::reverse<Iterable>(r);47 | }48 |49 | #include <iostream>50 |51 | int main()52 | {53 | int x[] {1, 2, 3, 4, 5, 6, 7, 8, 9};54 | for(int i : x)55 | {56 | std::cout << i << ' ';57 | }58 | std::cout << std::endl;59 | for(int i : reverse(x))60 | {61 | std::cout << i << ' ';62 | }63 | std::cout << std::endl;64 | }65 |

Segment RecapSegment Recap

● new syntax new syntax for(element : range-object) statementfor(element : range-object) statement● it is concise, safe, efficient, intuitive, and extensibleit is concise, safe, efficient, intuitive, and extensible● user-defined types can be easily tailored to work with the syntaxuser-defined types can be easily tailored to work with the syntax● ranges can easily be reverse-iterated with the syntaxranges can easily be reverse-iterated with the syntax● it can be conceptually viewed as synthetic code generationit can be conceptually viewed as synthetic code generation