generic programming and concepts that should be in c++

Post on 26-Jun-2015

310 Views

Category:

Engineering

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

My talk for ITMO students at fall 2009

TRANSCRIPT

Generic programmingAnton.Kolotaev@gmail.com

Generic Programming

• Programming paradigm for developing efficient, reusable software libraries

• Three primary tasks:• Categorize abstractions in a domain into

concepts• Implement generic algorithms based on

concepts• Build concrete models for the concepts

Characteristics of Generic Libraries

• Reusable: able to operate on user-defined types

• Composable: able to operate on data types defined in another library

• Efficient: performance on par with non-generic, hand-coded implementations

Generic Programming Process1. The Generic Programming process focuses on finding

commonality among similar implementations of the same algorithm, then providing suitable abstractions in the form of concepts so that a single, generic algorithm can realize many concrete implementations.

2. This process, called lifting, is repeated until the generic algorithm has reached a suitable level of abstraction, where it provides maximal reusability without sacrificing performance.

3. Dual to the lifting process is specialization, which synthesizes efficient concrete implementations for particular uses of a generic algorithm. Only by balancing the lifting and specialization processes can we ensure that the resulting generic algorithms are both reusable and efficient.

Lifting Basic Typesint sum(int* array, int n) { int result = 0; for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

float sum(float* array, int n) { float result = 0; for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

template<typename T>T sum(T* array, int n) { T result = 0; for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

Lifting Basic Typesstd::string concatenate(std::string* array, int n) { std::string result = ""; for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

// Requirements:// T must have a default constructor that produces the identity value// T must have an additive operator +// T must have an assignment operator// T must have a copy constructortemplate<typename T>T sum(T* array, int n) { T result = T(); for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

Lifting Containers

// Requirements:// T must have a default constructor that produces the identity // value// T must have an additive operator +// T must have an assignment operator// T must have a copy constructor// Container must have an indexing operator [] that returns a Ttemplate<typename Container, typename T>T sum(const Container& array, int n) { T result = T(); for (int i = 0; i < n; ++i) result = result + array[i]; return result;}

Lifting Iterationtemplate<typename T>struct list_node { list_node<T>* next; T value;};

struct linked_list { list_node<T>* start;};

template<typename T>T sum(list_node<T> list, int n) { T result = 0; for (list_node<T>* current = list.start; current != NULL; current = current->next) result = result + current->value; return result;}

Lifting Iteration// Requirements:// T must have an additive operator +// T must have an assignment operator// T must have a copy constructor// I must have an inequality operator !=// I must have a copy constructor// I must have an operation next() that moves to the next value in // the sequence// I must have an operation get() that returns the current value (of // type T).template<typename I, typename T>T sum(I start, I end, T init) { for (I current = start; current != end; current = next(current)) init = init + get(current); return init;}

Concepts// Requirements:// T must have an equality operator ==// T must have a copy constructor// I must have an inequality operator !=// I must have a copy constructor// I must have an assignment operator// I must have an operation next() that moves to the next value in // the sequence// I must have an operation get() that returns the current value // (of type T).template<typename I, typename T>I find(I start, I end, T value) { for (I current = start; current != end; current = next(current)) if (get(current) == value) return current; return end;}

ConceptsConcept Requirements

CopyConstructible<T> T must have a copy constructor

Assignable<T> T must have an assignment operator

Addable<T> T must have an operator+ that takes two T values and returns a T

EqualityComparable<T> T must have an operator== comparing two Ts and returning a bool.T must have an operator!= comparing two Ts and returning a bool.

Iterator<I, T> I must have an operator== comparing two Is and returning a bool.I must have an operator!= comparing two Is and returning a bool.I must have a copy constructor.I must have an assignment operator.I must have an operation next() that moves to the next value in the sequence.I must have an operation get() that returns the current value (of type T).

Concepts// Requirements: Addable<T>, Assignable<T>, CopyConstructible<T>, // Iterator<I, T>template<typename I, typename T>T sum(I start, I end, T init);

// Requirements: EqualityComparable<T>, Assignable<T>, // CopyConstructible<T>, Iterator<I, T>template<typename I, typename T>I find(I start, I end, T value);

Nested RequirementsConcept Requirements

Iterator<I, T> EqualityComparable<I>, CopyConstructible<I>, Assignable<I>I must have an operation next() that moves to the next value in the sequence.I must have an operation get() that returns the current value (of type T).

Associated TypesConcept Requirements

Iterator<I> EqualityComparable<I>, CopyConstructible<I>, Assignable<I>I must have an operation next() that moves to the next value in the sequence.value_type is an associated type, accessible via iterator_traits<I>::value_typeI must have an operation get() that returns the current value (of type value_type).

// Requirements: Iterator<I>, Addable<value_type>, // Assignable<value_type>, CopyConstructible<value_type>template<typename I>typename iterator_traits<T>::value_type sum(I start, I end, typename iterator_traits<T>::value_type init) { for (I current = start; current != end; current = next(current)) init = init + get(current); return init;}

template<typename T>struct iterator_traits<T*> { typedef T value_type; };

Concept RefinementConcept Requirements

BidirectionalIterator<I> Refines Iterator<I>I must have an operation prev() that moves to the previous value in the sequence.I must have an operation set() that sets the current value.

Specialization// Requirements: Polygon<P>template<typename P>double circumference(P p) { double result = 0; for (int i = 0; i < num_sides(p); ++i) result += side_length(p, i); return result;}

// Requirements: EquilateralPolygon<P>template<typename P>double circumference(P p) { return num_sides(p) * side_length(p, 0);}

Anatomy of a ConceptA concept is a set of requirements consisting of valid expressions, associated types,

invariants, and complexity guarantees. A type that satisfies the requirements is said to model the concept. A concept can extend the requirements of another concept, which is called refinement.

• Valid Expressions are C++ expressions which must compile successfully for the objects involved in the expression to be considered models of the concept.

• Associated Types are types that are related to the modeling type in that they participate in one or more of the valid expressions. Typically associated types can be accessed either through typedefs nested within a class definition for the modeling type, or they are accessed through a traits class.

• Invariants are run-time characteristics of the objects that must always be true, that is, the functions involving the objects must preserve these characteristics. The invariants often take the form of pre-conditions and post-conditions.

• Complexity Guarantees are maximum limits on how long the execution of one of the valid expressions will take, or how much of various resources its computation will use.

Traits classesA traits class provides a way of associating information with a compile-time

entity (a type, integral constant, or address) in non-intrusive (!!!) way

template <class T>struct iterator_traits <T*>{ typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T& reference;};

namespace std { struct input_iterator_tag { }; struct bidirectional_iterator_tag : input_iterator_tag { }; struct random_access_iterator_tag : bidirectional_iterator_tag { };

template <class InputIterator, class Distance> void advance(InputIterator& i, Distance n) { typename iterator_traits<InputIterator>::iterator_category category; detail::advance_dispatch(i, n, category); }}

Tag Dispatching

Tag Dispatching namespace detail { template <class InputIterator, class Distance> void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag ) { while (n--) ++i; }

template <class BidirectionalIterator, class Distance> void advance_dispatch(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag ) { if (n >= 0) while (n--) ++i; else while (n++) --i; }

template <class RandomAccessIterator, class Distance> void advance_dispatch(RandomAccessIterator& i, Distance n, random_access_iterator_tag ) { i += n; }

Fragile C++ Templatestemplate <class InputIterator, typename T>InputIterator find(InputIterator first, InputIterator beyond, const T& value){ while (first < beyond && !(*first == value)) ++first; return first;};

std::vector<int> v;find(v.begin(), v.end(), 42); // Ok

std::list<int> l;find(l.begin(), l.end(), 42); // error

Concepts for C++: Goals

• Support for the core ideas of GP in C++• Modular type checking for C++ templates• Performance equivalence to C++ templates• Complete backward compatibility• Simplicity• C++0x

Concepts Overview

• Concepts definitions: Specify the behaviour of types via requirements

• Where clauses: Specify constraints on template parameters in terms of concepts

• Concept maps: Specify how types meet the requirements of concepts

Constrained Templates

• Place constraints on template parameters via a where clause

template <typename T> where LessThanComparable<T> const T& min(const T& x, const T& y){ return x < y ? x : y;}

Concept Definitions

• Concept definitions state requirements on type parameters

concept LessThanComparable<typename T> { bool operator < (T, T);

axiom Irreflexivity(T x) { !(x < x); }

axiom Assymetry(T x, T y) { if (x < y) !(y < x); } axiom Transitivity(T x, T y, T z) { if (x < y && y < z) x < z; }}

Member Function Requirements

concept CopyConstructable<typename T> { T::T(T const &); // copy constructor T::~T(); // desctructor}

Iterators and Nested Requirementsconcept InputIterator <typename Iter> {

Iter& operator ++ (Iter&); Iter operator ++ (Iter&,int); bool operator == (Iter, Iter); bool operator != (Iter, Iter); ???? operator * (Iter);};

Iterators and Nested Requirementsconcept InputIterator <typename Iter> { typename value_type; typename difference_type; where SignedIntergral<difference_type>; Iter& operator ++ (Iter&); Iter operator ++ (Iter&,int); bool operator == (Iter, Iter); bool operator != (Iter, Iter); value_type operator * (Iter);};

Using Associated Typestemplate <class Iter, typename T> where InputIterator<Iter> && EqualityComparable<InputIterator<Iter>::value_type, T> Iter find(Iter first, Iter beyond, const T& value){ while (first != beyond && !(*first == value)) ++first; return first;};

Concept Maps

• Concept maps satisfy concept constraints

bool contains(int const * array, int n, int value) { return find(array, array + n, value) != array + n;}

template <class T>concept_map InputIterator<T*> { typedef T value_type; typedef ptrdiff_t difference_type;}

Concept Refinement// A bidirectional iterator can move backwardconcept BidirectionalIterator<typename Iter> : InputIterator<Iter>{ Iter& operator -- (Iter&); Iter operator -- (Iter&, int);}

// A random access iterator can jump aroundconcept RandomIterator<typename Iter> : BidirectionalIterator<Iter>{ Iter operator + (Iter, difference_type); // ...}

Concept-based overloadingtemplate <InputIterator Iter> void advance(Iter & x, Iter::difference_type n){ for (; n > 0; --n) ++x; // O(n)}

template <RandomAccessIterator Iter> void advance(Iter & x, Iter::difference_type n){ x += n; // O(1)}

top related