Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Easier C++: An Introduction to Concepts : Page 6

C++0x concepts bring the full power of the Generic Programming paradigm to C++, making templates more expressive, easier to write, and easier to use. Spectacularly poor template error messages are a thing of the past!

Concept Refinement and Concept-Based Overloading
It is often the case when implementing a generic algorithm that there are several possible implementations, each of which involves different trade-offs. Some implementations may apply to a wide variety of data types (are very generic) while others operate more efficiently on a more narrow range of data types (are more specialized). For example, the generic perimeter() algorithm operates on any polygon in linear time, but there is a more efficient implementation: If you know that the polygon is an equilateral polygon (where all sides have the same length), you could compute the perimeter with a single multiplication. Like Polygon, EquilateralPolygon is a concept that describes types that behave like polygons.

You could implement an EquilateralPolygon separately from the Polygon concept, but doing so misses an important opportunity for reuse, because every equilateral polygon is also a polygon. You can therefore express EquilateralPolygon as a refinement of the Polygon concept:

concept EquilateralPolygon<typename P> : Polygon<P> { }

As the syntax implies, concept refinement is similar to concept "inheritance," because the refining concept (EquilateralPolygon) inherits all of the base concept's requirements (Polygon). Additionally, a type that is an EquilateralPolygon can be used in any algorithm that expects a Polygon, meaning that this square class could be used with the existing perimeter() algorithm:

class square { public: int length; }; concept_map EquilateralPolygon<square> { typedef int length_type; int num_sides(const square&) { return 4; } int side_length(const square& sq, int) { return sq.length; } }

Concept refinement describes a hierarchical "is-a" relationship that can also be used by concept-based overloading, which involves overloading constrained templates on their requirements. As noted before, you can write a constant-time algorithm for computing the perimeter of an equilateral polygon, assuming you've already added a suitable multiplication operator to the Numeric concept:

template<EquilateralPolygon P> P::length_type perimeter(const P& poly) { return num_sides(poly) * side_length(poly, 0); }

This implementation of perimeter() overloads the previous, Polygon-based implementation. For types that are non-equilateral Polygons, the previous (linear-time) implementation will be used, because this (constant-time) constrained template's requirements will not be satisfied. For equilateral polygons like square, both implementations are valid because every equilateral polygon is a polygon. In this case, concept-based overloading picks the overload corresponding to the more refined concept, automatically selecting the constant-time implementation of perimeter(). Concept-based overloading (and, related, concept-based partial specialization of class templates) allows the user to provide multiple, different variations of the same algorithm, which differ only by the properties of the types that they support, and the compiler will select the most appropriate algorithm variation for each call site.

Truly Easier C++
Concepts are a significant extension to the C++ template system. By allowing template authors to explicitly describe the template requirements, the compiler is able to verify both the template author’s and the template user's side of the (previously implicit) template contract. This additional type checking makes it easier to write templates (because they cannot violate the stated contract) and use templates (because contract violations result in far more readable error messages). The use of template requirements also enables advanced features that make templates more reusable, such as the ability to remap syntax within concept maps, and more expressive, through the use of concept-based overloading.

As of this writing, concepts are expected to be included in the C++0x language and standard library. However, concepts have not yet been voted into the working paper by the ISO C++ standards committee, and some small details may still change. Watch for more interesting developments in C++0x and the concepts mechanism.

Douglas Gregor is an active member of the ISO C++ committee, where he has lead the development and specification of various C++09 features, including concepts and variadic templates. A long-time contributor to Boost, Doug has developed several Boost libraries and acts as a moderator for the Boost community. Doug is currently the assistant director of the Open Systems Lab at Indiana University, where his research involves generic programming, parallel programming, and large-scale graph analysis.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.