|
|
|
Advertisement
|
sort(v);To do that within the framework of the STL we must overload
sort for
containers and for iterators. For example:
template<Container C> // sort container using <
void sort(C& c);
template<Container C, Predicate Cmp> // sort container using Cmp
where Can_call_with<Cmp,typename C::value_type>
void sort(C& c, Cmp less);
template<Random_access_iterator Ran> // sort sequence using <
void sort(Ran first, Ran last);
template<Random_access_iterator Ran, Predicate Cmp> // sort sequence using Cmp
where Can_call_with<Cmp,typename Ran::value_type>
void sort(Ran first, Ran last, Cmp less);
This illustrates the most significant proposed C++0x language extension that is likely to be accepted: concepts.
Basically, a concept is the type of a type; it specifies the properties required of a type. In
this case, the concept Container is used to specify that the two first
versions of sort need an argument that meets the standard library
container requirements. The where-clauses are used to specify the
required relationship between the template arguments: that the predicates can be applied
to the containers' element types. Given concepts we can provide far better error
messages than is currently possible and distinguish between templates taking the same
number of arguments, such as
sort(v, Case_insensitive_less()); // container and predicateand
sort(v.begin(), v.end()); // two random access iteratorsThe difficulty in the design of �concept� is to maintain the flexibility of templates so that we don�t require template arguments to fit into class hierarchies or require all operations to be accessed through virtual functions (as for Java and C# generics). In �generics�, an argument must be of a class derived from an interface (the C++ equivalent to �interface� is �abstract class�) specified in the definition of the generic. That means that all generic argument types must fit into a hierarchy. That imposes unnecessary constraints on designs requires unreasonable foresight on the part of developers. For example, if you write a generic and I define a class, people can't use my class as an argument to your generic unless I knew about the interface you specified and had derived my class from it. That's rigid.
There are workarounds, of course, but they complicate code. Another problem is that you
cannot use built-in types directly with generics, because built-in types, such as
int, are not classes and don't have the functions required by interfaces
specified by a generic—you then have to make wrapper classes for holding built-in
types and access elements indirectly through pointers. Also, the typical operation on a
generic is implemented as a virtual function call. That can be very expensive (compared
to just using a simple built-in operation, such as + or <). Implemented that way,
generics are simply syntactic sugar for abstract classes.
Given "concepts", templates will retain their flexibility and performance. There is still much work left before the committee can accept a specific and detailed concept design. However, concepts are a most likely extension because they promise significantly better type checking, much better error messages, and greater expressive power. That should lead to significantly better library interfaces, starting with the current standard containers, iterators, and algorithms.
Finally, consider the last line that outputs the elements of our vector:
for (auto p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
The difference from C++98 here is that we don�t have to mention the type of the iterator:
auto means �deduce the type of the declared variable from the
initializer�. Such uses of auto are far less verbose and also less
error-prone than current alternatives, such as:
for (vector< double, My_alloc<double> >::const_iterator p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
The new language features mentioned here are all aimed at simplifying generic
programming. The reason is that generic programming has become so popular that it is
seriously strains the language facilities. Many �modern� generic programming techniques
border on �write only� techniques and threaten to isolate its users. To make generic
programming mainstream, as object-oriented programming was made mainstream, we
must make template code easier to read, write, and use. Many current uses are too clever
for their own good. Good code is simple (relative to what it is trying to do), easy to
check, and easy to optimize (i.e., efficient). This implies that a wide range of simple ideas
can be expressed simply in C++0x and that the resulting code is uncompromisingly
efficient. The former is not the case in C++98—at least not for a sufficiently large
range of techniques relying on templates. Better type checking and more extensive use of
type information to shorten code will make code shorter and clearer, and easier to maintain,
as well as more likely to be correct.
unordered_maps) available. In
addition, the Library TR provides extensive facilities for builders of generic libraries
building on the STL:
The list of proposals is still quite modest and not anywhere as ambitious as I�d like. However, more proposals from the committee's large backlog of suggestions are being considered and more libraries will appear either as part of the C++0x standard itself or as further committee technical reports. Unfortunately, lack of resources (time, money, skills, people, etc.) will continue to limit progress in this direction. Sadly, I cannot offer hope for the most frequently wished for new standard library: a standard GUI library. A GUI library is simply too large a task for the volunteers of the C++ standards committee to handle and too difficult a task given the many (non-standard but huge, useful, and supported) GUI libraries available. Please notice that even though they are not standard, the major C++ GUIs have more users than most programming languages and are often better supported.
In addition to these general-purpose libraries, the committee presented a library interface to the most basic level of hardware in its �Performance TR�. That TR is primarily aimed to help embedded systems programmers and to disprove myths about poor performance of C++ code and about C++ being unsuitable for low-level tasks.
template<Container C>
void draw_all(C& c)
where Usable_as<typename C::value_type,Shape*>
{
for_each(c, mem_fun(&Shape::draw));
}
In C++0x, we hope to have Container as a standard concept and Usable_as
as a standard predicate. The
for_each algorithm is already in C++98, but the version that takes a
container (rather than a pair of iterators) will have to wait for concepts in C++0x. The
where-clause is a mechanism through which an algorithm can express
requirements on its arguments. Here, draw_all() requires (obviously) that
the elements of the container must be usable as (implicitly convertible to)
Shape*. In this case, the where-clause gives us a degree of
flexibility/generality not offered by simply requiring a container of
Shape*'s. In addition to any container of Shape*'s, we can
use any container with elements that can be used as Shape*'s, such as a
list<shared_ptr<Shape*>> (where
shared_ptr is a likely C++0x standard library class) or a container of
pointers to a class derived from Shape*, such as
deque<Circle*>.
Assuming that we have points p1, p2, and p3, we can test
draw_all() like this
vector<Shape*> v = {
new Circle(p1,20),
new Triangle(p1,p2,p3),
new Rectangle(p3,30,20)
};
draw_all(v);
list<shared_ptr<Shape*>> v2 = {
new Circle(p1,20),
new Triangle(p1,p2,p3),
new Rectangle(p3,30,20)
};
draw_all(v2);
The "draw all shapes" example is important because when you can do that well, you can
do much of what�s key to object-oriented programming. As written here, the example
demonstrates the power of multi-paradigm programming by also employing generic
programming (concepts and templates), conventional programming (e.g. the
free-standing standard-library function mem_fun()), and simple data
abstraction (the function object returned by mem_fun()). Thus, this
simple example opens the door to a host of elegant and efficient programming
techniques.
I hope that after looking a bit at this example, your reaction will be "How simple!" rather
than "How clever! How advanced!" In my opinion, many people are trying too hard to
be clever and advanced. The real aim of design and programming is to produce the
simplest solution that does the job and express it in the clearest possible way. The aim of
the C++0x design is to better support such simple solutions.
|
Sponsored Links
|