By codemonkey_uk in Columns Thu Mar 01, 2001 at 10:00:35 AM EST Tags: Software (all tags) | ||
In the past, reusable code meant a sacrifice of efficiency for convenience. The C standard library C++ introduces generic programming, with templates, eliminating the need for runtime binding, but at first glance this still looks like a compromise, after all, the same algorithm will not work optimally with every data structure. Sorting a linked list is different to sorting an array. Sorted data can be searched much faster than unsorted data. The C++ traits technique provides an answer. Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details".Both C and C++ programmers should be familiar with limits.h , and float.h , which are used to determine the various properties of the integer and floating point types. Most C++ programmers are familiar with Using
Note the use of numeric_limits . As you can see, where as with the C style limits.h idiom, where you must know the type, with the C++ traits idiom, only the compiler needs to know the type. Not only that, but numeric_limits , as with most traits, can be extended to include your own custom types (such as a fixed point, or arbitrary precision arithmetic classes) simply by creating a specialisation of the template. But I'd like to move away from First lets look at one of the simplest traits classes you can get (from boost.org) and that's the First, a generic template is defined that implements the default behaviour. In this case, all but one type is void, so
Add to that a specialisation for void:
And we have a complete traits type that can be used to detect if any given type, passed in as a template parameter, is void. Not the most useful piece of code on its own, but definitely a useful demonstration of the technique. Now, while fully specialised templates are useful and in my experiance, the most common sort of trait class specialisation, I think that it is worth quickly looking at partial specialisation, in this case,
And a partial specialisation for all pointer types is added:
So, having got this far, how can this technique be used to solve the lowest common denominator problem? How can it be used to select an appropriate algorythm at compile time? This is best demonstrated with an example. First a default traits class is created, for this example we'll call it
Next the a specialisation of algorithm_selector is added which, in this case, passes the responsability for implementing the algorithm back to the author of the object being operated on, but could well implement a second version of the operation itself.
Then we write the generic function that the end user of your algorithm will call, note that it in turn calls algorithm_selector , parameterised using our supports_optimised_implementation traits class:
Now all that's left to do is test it against a class that doesn't support the feature ( class ObjectA{}; ), and a class that does:
Finally, instantiate the templates:
[ Link: C++ Traits Example Source Code in full. ] And that's it. Hopefully you can now "wow" your friends and colleague with your in-depth understanding of the c++ traits concept. :) Notes It should be noted that the examples in this article require a cutting edge, standard compliant, compiler. For example, MSVC++ 6.0 does not support static constants, and will balk on:
This particular problem can be worked around by using an enum in its place, ie:
Please contact your compiler vendor for appropriate work arounds and bug fixes for your platform. By Thad References & further reading
|
Programming Tips: 2) An introduction to C++ Traits
最新推荐文章于 2024-10-02 22:25:35 发布
Programming Tips: 2) An introduction to C++ Traits