240 likes | 504 Views
Concepts: Linguistic Support for Generic Programming in C++. Jaakko Järvi Bjarne Stroustrup Andrew Lumsdaine. Douglas Gregor Jeremy Siek Gabriel Dos Reis. Generic Programming. A methodology for the construction of generic software libraries. Dual focus on abstraction and efficiency
E N D
Concepts: Linguistic Support for Generic Programming in C++ Jaakko Järvi Bjarne Stroustrup Andrew Lumsdaine Douglas Gregor Jeremy Siek Gabriel Dos Reis
Generic Programming • A methodology for the construction of generic software libraries. • Dual focus on abstraction and efficiency • Example: The C++ Standard Template Library • Core notion: Lifting an algorithm • Start with concrete algorithms: int gcd(int a, int b) { ... } • Remove unnecessary requirements:template<typename Integral> Integral gcd(Integral a, Integral b) { ... } • Repeat: lift Integral to CommutativeRing
Generic Programming in C++ • C++ templates enable the application of GP • Overloading permits natural abstractions • Instantiation eliminates cost of abstractions • Many successful, generic libraries in C++ • Significant problems remain: • Inability to directly express ideas of GP • Generic libraries in C++ are fragile Can we design better support for Generic Programming in C++ without sacrificing the performance and flexibility of templates?
Concepts for C++: Goals • Support for the core ideas of Generic Programming in C++ • Modular type checking for C++ templates • Performance equivalent to C++ templates • Complete backward compatibility • Library evolution is particularly important • Simplicity • Implementability
Concepts Overview • Three major parts: • Concept definitions: Specify the behavior of classes of types via requirements. • Where clauses: Specify constraints on template parameters in terms of concepts. • Concept maps: Specify how types meet the requirements of a concept.
Constrained Templates • Place constraints on template parameters via a where clause • Uses of the template must satisfy these constraints • Definition of the template can assume only what the constraints imply 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 Transitivity(T x, T y, T z) { if (x < y && y < z) x < z; } }
Concept Parameterization • Concepts can have any number of parameters: concept EqualityComparable<typename T, typename U> { bool operator==(T, U); bool operator!=(T, U); }
Iterator Concepts • Iterators abstract the notion of a sequence of values. concept InputIterator<typename Iter> { Iter& operator++(Iter&); // pre-increment Iter operator++(Iter&, int); // post-increment bool operator==(Iter, Iter); // equality comparison bool operator!=(Iter, Iter); // inequality comparison ??? operator*(Iter); // dereference };
Iterators & Associated Types • value_type is the type that the iterator points to concept InputIterator<typename Iter> { typename value_type; Iter& operator++(Iter&); // pre-increment Iter operator++(Iter&, int); // post-increment bool operator==(Iter, Iter); // equality comparison bool operator!=(Iter, Iter); // inequality comparison value_type operator*(Iter); // dereference };
Iterators & Nested Requirements • difference_type measures sequence length concept InputIterator<typename Iter> { typename value_type; typename difference_type; where SignedIntegral<difference_type>; Iter& operator++(Iter&); // pre-increment Iter operator++(Iter&, int); // post-increment bool operator==(Iter, Iter); // equality comparison bool operator!=(Iter, Iter); // inequality comparison value_type operator*(Iter); // dereference };
Using Associated Types • Implementing the STL find with concepts: template<typename Iter, typename T> where InputIterator<Iter> && EqualityComparable<InputIterator<Iter>::value_type, T> Iter find(Iter first, Iter last, const T& value) { while (first != last && !(*first == value)) ++first; return first; }
Concept Maps • We want to call find with an array of integers: bool contains(int* array, int n, int value) { return find(array, array + n, value) != array + n; } • Concept maps satisfy concept constraints: concept_map InputIterator<int*> { typedef int value_type; typedef ptrdiff_t difference_type; }
Concept Maps • We want to call find with an array of integers: bool contains(int* array, int n, int value) { return find(array, array + n, value) != array + n; } • Concept maps satisfy concept constraints: template<typename T> concept_map InputIterator<T*> { typedef T value_type; typedef ptrdiff_t difference_type; }
Concept Refinement • A bidirectional iterator can move backward: concept BidirectionalIterator<typename Iter> : InputIterator<Iter> { Iter& operator--(Iter&); Iter operator--(Iter&, int); } • A random access iterator can jump around: concept RandomAccessIterator<typename Iter> : BidirectionalIterator<Iter> { Iter operator+(Iter, difference_type); // … } Input Iterator Bidirectional Iterator Random Access Iterator
Concept-Based Overloading • Advance an iterator x by n steps: template<InputIterator Iter> void advance(Iter& x, Iter::difference_type n) { while (n > 0) { ++x; --n; } } // O(n) template<RandomAccessIterator Iter> void advance(Iter& x, Iter::difference_type n) { x = x + n; } // O(1) • Compiler selects best match: • advance(i, n); // O(1) or O(n)? • Overloaded calls in generic algorithms can cause instantiation-time ambiguities (PLDI ‘06)
Concept Maps for Composition leda::GRAPH<Server, Link> internet_graph; leda::edge_array<double> total_latency; boost::shortest_paths(internet_graph, start, total_latency);
Concept Maps for Composition template<typename V, typename E> concept_map Graph<leda::GRAPH<V, E> > { typedef leda::leda_node vertex_type; int num_vertices(const leda::GRAPH<V, E>& g) { return g.number_of_nodes(); } int out_degree(vertex_type v, const leda::GRAPH<V, E>&) { return outdeg(v); } };
Concept Maps for Composition leda::GRAPH<Server> internet_graph; leda::edge_array<double> eigenvector; double eigenvalue = ietl::compute_eigenvector(internet_graph, eigenvector, 0);
Concept Maps for Composition template<typename V, typename E> concept_map Matrix<leda::GRAPH<V, E> > { // ... };
Concept Maps for Composition template<typename G> where Graph<G> concept_map Matrix<G> { // ... };
Related Work • G • Haskell Type Classes • ML Signatures • Java, C# Generics • Fortress Traits
Summary: Concepts for C++ • Concepts provide complete support for Generic Programming in C++ • Transparent composition of generic libraries • Seamless evolution of existing C++ code • Prototype implementation in ConceptGCC • Includes drop-in concept-enhanced STL http://www.generic-programming.org/software/ConceptGCC • Strong candidate for inclusion in upcoming ISO C++ Standard, C++0x