Dynamic languages need to be constantly changed and growing, and C ++ is no exception. In this article, Bjarne Stroustrup puts forward his own views on the design and evolution of C ++.
In order to keep compilers, tools, and class library implementers up to date, and to allow users to absorb the programming technologies supported by standard C ++, after a few years of foresight and silence, the Committee once again considered Language extension issues. The "extended workgroup" has been established, replacing the "Evolution workgroup ". Name changes (this is Tom Plum's suggestion) reflect more importantly the integration of language features and standard library tools. I am still the Chairman of the Working Group. I hope this will ensure the consistency of the C ++ version and the final result. Similarly, committee membership shows the continuous participation of a large number of people and organizations. Fortunately, many new faces have emerged, bringing new influences and new expert opinions to the Committee.
We intend to be cautious and conservative about changes in the language, with emphasis on compatibility. The main purpose is to direct the main efforts to the expansion of standard class libraries. In terms of standard libraries, our goal is to be bold and take advantage of all opportunities.
For a standard class library, I hope to establish it based on the elements of the class library technical report to make it a broader platform for system programming. For example, I want to see class libraries for some fields, such as directory/folder operations, threads, and sockets. I also hope that the Committee will sympathize with many new C ++ programmers and provide class library tools to support beginners with different backgrounds (not new programmers and C refugees ). For example, I want to see a standard method that uses the range check STL. I have very low expectations for the standard GUI (graphical user interface) that is most frequently requested to be added to the standard class library. However, miracles sometimes happen-remember STL?
For the language itself, I hope to emphasize the support for the features of generic programming, because generic programming is the most advanced field of language use. Here, I will investigate two key parts:
· Concept (Concepts): Type System Used for template parameters
· Initializer list: generalization of the initialization Tool
As in the past, the number of recommendations still far exceeds the number that the Committee can process and that language can absorb. Remember, it is impossible to accept all the good suggestions.
The purpose of this language extension to support generic programming is to provide greater consistency for tools, allowing us to directly represent classes used to solve problems with generics.
My other priorities (together with better support for generic programming) are better support for beginners. The current recommendations have a noteworthy tendency to take care of expert users who propose and evaluate suggestions. Some suggestions for helping new users are often ignored. I think this is a potentially fatal design preference. Unless the novice is fully supported, only a few can become experts. In addition, many people do not want to become experts; they still want to be "occasional C ++ users ". For example, physicists who use C ++ for physical computing or control test equipment spend only a limited amount of time learning programming techniques. Computer experts may spend a lot of time on programming technology, not just expectations. We must eliminate unnecessary obstacles to adopting excellent technologies.
An example is as follows:
vector<vector<double>> v;
In C ++ of 98 years, this will lead to syntax errors, because> is a separate word mark, rather than two closed template parameter lists>. V's correct statement may be:
vector< vector<double> > v;
I regard it as a hindrance. I once suggested that this problem should be solved, but the current rule and evolution Working Group used some good reasons to reject my suggestion twice. However, these reasons are all about language technology, and new users (including experts in other languages) are not interested. Disaccepting the first (and very) Obvious v statement wastes user and instructor time. I hope> problems and other similar "obstacles" should not appear in C ++ 0x any more. Actually, together with Francis Glassborow and others, I am systematically trying to eliminate the most frequent "obstacles ".
Another "obstacle" is that it is legal to copy class objects with user-defined destructor using the default copy operation (construction or assignment. In this case, user-defined replication operations are required to eliminate a large number of troublesome errors related to resource management. For example, consider the over-simplified string class below:
class String {
public:
String(char* pp) :sz(strlen(pp)), p(new char[sz+1]) { strcpy(p,pp); }
~String() { delete[] p; }
char& operator[](int i) { return p[i]; }
private:
int sz;
char* p;
};
void f(char* x)
{
String s1(x);
String s2 = s1;
}
After s2 is constructed, s1.p and s2.p point to the same memory area, and this memory is deleted twice, which may cause disastrous consequences. This problem is obvious to experienced C ++ programmers who generally provide appropriate replication operations or prohibit replication. However, this problem will seriously affect new users and undermine their trust in the language.
Disabling the default replication behavior of class objects with pointer members may be better, but this may cause annoying compatibility issues. Fixing long-standing problems is much more difficult than the surface looks complicated, especially when considering C compatibility.
1. Concept (Concepts)
D & E (Editor's note: "C ++ design and evolution" is generally referred to as D & E) the constraints on template parameters contained in the template discussion take up three full pages. Obviously, I think a better solution is needed. The error message caused by minor errors in the use of templates (such as standard library algorithms) may be very long and does not help us. This problem is because the template code absolutely believes in its own template parameters. Take a look at find_if () below ():
template<class In, class Pred>
In find_if(In first, In last, Pred pred)
{
while (first!=last && !pred(*first)) ++first;
return first;
}
In the above Code, we make many assumptions about the In and Predicate types. We can see from the code that, for some reason, In must be supported with appropriate Semantics! =, * And ++, and we must be able to copy In objects as parameters and return values. Similarly, we can see that we can call a Pred. Its parameter is * (value operator) of any type returned from In and applied to the result! Operator, which can be regarded as boolean. However, all these are implicit in the code. The standard library carefully records these requirements of the forward iterator sub (In this example) and the Pred, but the compiler does not read the manual. Try the following error to see the error message displayed by your Compiler:
Find_if (3.14,); // Error
The solution based on my old idea-let the constructor check the hypothetical conditions of template parameters-is currently widely used. For example:
Template <class T> struct Forward_iterator {
Static void constraints (T ){
++ A; a ++; // you can add
T B = a; // copy
* B = * a; // The result can be discarded or copied.
}
Forward_iterator () {void (* p) (T) = constraints ;}
};
The code above defines a class, which can be compiled only when T is a forward iterator. However, the Forward_iterator object does not perform any actual transactions, so the compiler can only (and indeed) perform minor optimization operations on such objects. We can use Forward_iterator in the following definition:
Template <class In, class Pred>
In find_if (In first, In last, Pred pred)
{
Forward_iterator <In> (); // check the template parameter type.
While (first! = Last &&! Pred (* first) ++ first;
Return first;
}
Alex Stepanov and Jeremy Siek have done a lot of work to develop and popularize this technology. One of the places they use this technology is the Boost class library, but currently you will find the constraint class in most standard class library implementations. The quality of error messages varies greatly.
However, the constraint class is an incomplete solution at most. For example, test in definition-if the check can only be completed in declaration, it will be much better. When using this method, we must follow the Interface Usage rules and begin to consider the possibility of separate template compilation.
Therefore, let's tell the compiler the template parameters we expect:
template<Forward_iterator In, Predicate Pred>
In find_if(In first, In last, Pred pred);
Suppose we can indicate what Forward_iterator and Predicate are, then the compiler can ignore its definition and independently check the find_if () call. In this case, we need to create a type system for the template parameters. In modern C ++ environments, this "type of type (types of types)" is called "concept (concepts )". We can illustrate this concept in many ways. From now on, we want to think of them as constraints that are directly supported by the language and have better syntax. A concept illustrates what tools are required for a type, rather than how they are provided. The concept of perfection (for example, <Forward_iterator In>) is very similar to that of mathematical abstraction ("for all types of In, In can be added, destroyed, and copied, just as the original <class T> is mathematical "for all types of T ".
After the find_if () Statement is given (and not defined), we can write
int x = find_if(1,2,Less_than<int>(7));
This call will fail because int does not support *. In other words, this call fails during compilation because int Is Not A Forward_iterator. It makes it easy for the compiler to report errors in the user language, and the call will be first seen during compilation.
Unfortunately, knowing that the sub-parameter of the iteration is Forward_iterator and that the Predicate parameter is not enough to ensure that the find_if () call is successfully compiled. These two parameters affect each other. In particular, the pred parameter is an iterator that uses * (pred (* first) to release the reference. Our goal is to improve the template detection in the case of separation from the call, and improve the inspection of each call without viewing the template definition, therefore, the concept must have sufficient performance to process such iterations in template parameters. One way is to use parallel parameters to represent the concept, which is similar to the parameterization method of the template. For example:
Template <Value_type T,
Forward_iterator <T> In, // The iterator is In the T sequence.
Predicate <bool, T> Pred> // carries the T parameter and returns a Boolean value.
In find_ I