Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

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

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!


advertisement
Associated Requirements
Adding the Numeric requirement to the perimeter() concept is correct, but it is not ideal. The requirement that the length_type of a Polygon be Numeric isn't solely a property of perimeter(): It's a more universal property that polygons only make sense if their length types are proper numeric types. To support this common usage, concepts support associated requirements, which specify extra requirements on the associated types of a concept within the concept body. Here is the final version of the Polygon concept, which makes use of associated requirements:

concept Polygon<typename P> { typename length_type; requires Numeric<length_type>; int num_sides(const P&); length_type side_length(const P&, int index); }

With this change, you can remove the explicit Numeric requirement from the perimeter() algorithm, because the length type of a Polygon is always numeric. For the final declaration of this perimeter() algorithm, I've also employed two syntactic shortcuts, which simplify the expression of template requirements and simplify access to associated types:

template<Polygon P> P::length_type perimeter(const P& poly);

The first shortcut is the use of Polygon P, which states that P is a template type parameter whose requirement is Polygon<P>; it is identical to writing the same requirement within a requires clause. The second shortcut is the use of P::length_type, which searches for an associated type named length_type within the requirements placed on P, and is identical to Polygon<P>::length_type.



Syntax Remapping with Concept Maps
All the concept maps so far have had empty bodies within their curly braces, and have been used to state (and check) that a type meets the concept requirements. However, concept maps need not be empty: they can contain definitions that specify how a type meets the concept requirements, and can even contain new functions that allow one to map the syntax provided by a type to the syntax expected by the concept. For example, start with a simple rectangle structure:

struct rectangle { double left, top, right, bottom; };

You could add appropriate num_sides() and side_length() functions to this type to make it look like a Polygon. But, this expands the interface in a way that might not be desirable if the only purpose is to use the perimeter() function. Instead, you can write a concept map that makes the rectangle look like a polygon:

concept_map Polygon<rectangle> { typedef double length_type; int num_sides(const rectangle&) { return 4; } double side_length(const rectangle& rect, int index) { return index % 2? fabs(rect.right – rect.left) : fabs(rect.bottom – rect.top); } }

In this concept map, the Polygon concept's requirements are satisfied by the body of the concept map itself. The functions provided by the concept map are visible only through the concept itself, and are not part of the public interface of the rectangle structure (which has not changed). Only those constrained templates that operate on Polygons will see this particular view of the rectangle structure.

Through this syntax-remapping mechanism, an existing type can be adapted to meet an existing concept's requirements without changing either the type or the concept, allowing far greater reuse of generic algorithms than is possible without concept maps.



Comment and Contribute

 

 

 

 

 


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

 

 

Sitemap