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
 

Template Constraints Are So 1997; Usher in C++09 Concepts-3 : Page 3

Puzzled by indecipherable template compilation errors? Still struggling in vein to enforce restrictions on template parameters? It's time you migrated C++09 concepts!


advertisement

Sordid? Out!
Concepts are a new C++09 feature. At least one compiler supports this feature already; other implementations will soon follow suit. <p,> Concepts work like this: You augment a template declaration with a set of policies and constraints called concepts. When a template is instantiated, the compiler checks whether the instantiation complies with that template's concepts. If all is well, the template is instantiated successfully. Otherwise, a compilation diagnostic is issued stating which constraints(s) were violated.

Let's look at a concrete example. The std::min()algorithm is defined as follows:


template<typename T> //typical C++03 min()
inline const T& min(const T& x, const T& y) 
{
 return x < y? x : y;
}


As with std::sort(), std::min() imposes a constraint on its parameter T: "T shall be a type that has a less-than operator which takes two references to const T and returns bool." You express this requirement by embedding a concept directly in the definition of min():


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

Instead of stating that T is an arbitrary type, this template definition states that T shall be LessThanComparable, whatever that is. If you instantiate min() with an argument that isn't LessThanComparable, the compiler will catch the error early and report that the argument of min() doesn't satisfy the LessThanComparablerequirement.

A concept definition uses the C++09 keyword conceptfollowed by the name of the concept and a template parameter list:


auto concept LessThanComparable <typename T> {/*...*/}  

The concept body contains a list of declarations that state the requirements with which the template parameter(s) must comply (I will explain the role of auto shortly). A complete definition of the LessThanComparableconcept looks like this:


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

LessThanComparable states that the template parameter T shall be a type that has a less-than operator which takes two T objects as arguments and returns bool. auto in this context indicates that any type that has an operator< will qualify as LessThanComparable. If you omit auto from this concept, users will have to explicitly state that their types are LessThanComparable by using a concept map, which I will not discuss here for the sake of brevity.

Suppose you need another concept called Regular that denotes any type can be constructed, copied, assigned to, compared, destroyed, and swapped. The Regular concept definition uses concept signatures, each of which denotes a different requirement:


auto concept Regular<typename T> 
{
//each signature denotes a different requirement
 T::T(); // constructible
 T::T(const T&); // copyable
 T& operator=(T&, const T&); // assignable
 T::˜T(); // destructible 
 bool operator==(const T&, const T&); //comparable
 void swap(T&, T&); // swappable
};

Regulardenotes any type that:

  • Has all four canonical member functions
  • Can be compared using operator==
  • Can be swapped by calling swap()

std::string, int and vector <double> qualify as Regular. However, std::ofstreamdoesn't because it's neither assignable nor copyable.

A concept can apply to more than one type. For instance, a Convertible concept guarantees that there shall be an implicit conversion from T to U:


auto concept Convertible <typename T, typename U> {
operator U(const T&);
};

Such a concept is typically used in a where-clause. The convert() function template uses a where-clause to ensure that its argument is convertible to the return type:


template 
 where Convertible<T, U>
U convert(const T& t) 
{
 return t;
}
float f=convert<float>(5);//OK, int to float
float* p=convert<float*> (6); //error, int to float*  

Apart from the where-clause, this is an ordinary C++03 template.

There's More to Concepts
The concepts proposal includes other features that enable you not just to enforce requirements on template parameters but to write complete algorithms using concepts, or alter the implementation of an existing interface, for example implementing a stack using a vector by matching a Stack concept with a concept map that maps std::vector operations with std::stackoperations. Future 10 Minute Solutions will be dedicated to such advanced concepts features.



Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Comment and Contribute

 

 

 

 

 


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

 

 

Sitemap