Overload 4 hit my desk shortly after I returned from San Diego and the most recent meeting of X3J16/WG21. San Diego’s a beautiful city and this was the first occasion that I had taken time off around a committee meeting to explore. I hope we get back there before we’ve finished the standardisation process. The schedule for future meetings is gradually being laid out and the following international members will be hosting meetings in the next few years: Canada (July ‘94), Japan (November ‘95), Sweden (July ‘96), UK (July ‘97). In addition, there are two meetings a year in North America – well, the U.S. folks don’t travel too well, you see…
The UK meeting will be hosted by my company, and by that time we should be fairly close to an international standard. All the same, it would be nice to see as large a UK contingent present as possible.
What happened in San Diego?
The hot topic was the schedule – not just the planned meetings, but the more important issue of how quickly we can produce an International Standard for C++.
The UK Position
Prior to the meeting, the UK panel had been reviewing the working paper and had come to the conclusion that it really was a long way off being acceptable as an IS. Accordingly, we took the position that we wanted to slip the schedule by two meetings, or eight months.
By the time myself and Steve Rumsby arrived in San Diego, we had established, informally at least, that the UK position was supported by Germany, Japan, Australia and New Zealand. That meant a majority of the international members supported a slippage. However, we sort of didn’t get it…
The “missing” Ballot
The schedule prior to San Diego said we would be voting in July ‘94 on whether to advance the working paper into the “CD Registration Ballot”. This ballot is conducted by SC22 – an international committee for which WG21 is an advisory working group. From there the document would go on to “Draft International Standard” and finally “International Standard”, assuming it was successful at each ballot.
Sam Harbison, convenor of WG21, informed us that there was in fact an extra ballot involved between “CD Registration” and “DIS”. Adding this to the schedule pushed the final date out by about eight months.
There ensued a great deal of confusion about exactly what each ballot meant and what the criteria for acceptance at each stage should be. In the end, the “pro-slip” group agreed to delay a decision on whether or not to slip until the July meeting. Our main opponent was the U.S. who seems indecently keen to have a standard now and damn the quality. The July meeting will be interesting and will be held, somewhat prophetically, in Waterloo (in Canada!).
If all goes well
According to the schedule produced at the end of the San Diego meeting (which was not, perhaps significantly, endorsed by the majority of WG21 members), we should publish our International Standard for C++ early in 1997.
So why did I say that the July ‘97 meeting will be in the UK? Well, no-one really believes that the document will go through each and every one of the three ballots first time. Even if it did, we would still be answering public interpretation requests for years to come.
Language changes
Apart from the schedule, it was business as usual for most of the working groups. Core continued to wrestle with linkage, references and lvalues. Library continued wrestling with iostream and began to get to grips with exceptions. Extensions wrestled with exceptions and templates.
I’ve broken it
Or rather, we’ve finally fixed it: the scope of variables declared in a for loop, that is. You may not thank the committee for it now, but we broke this:
for(int i = 0; i < LIMIT; ++i)
{
if (key == table[i])
{
break;
}
}
if (i == LIMIT)
{
// didn't find the key item
}
We have made i go out of scope at the end of the for loop. A lot of code does this, but it is very easy to fix:
int i = 0;
for ( ; i < LIMIT; ++i)
This restores the original meaning. Why did we change it? A lot of people new to C+ + write something like this and wonder why it doesn’t work:
for(int i=O;i < LIMIT;++i)
...
for(int i=O;i < LIMIT;++i)
...
The second for loop causes a “duplication definition” compilation error. Furthermore, there’s a quality issue involved: if you really want to ask whether or not an item is present in the table, shouldn’t you choose a better way than testing the loop variable?
bool missing = true;
for(int i=0; i < LIMIT; ++i)
{
if (key == table[i])
{
missing = false;
break;
}
}
if (missing)
{
// didn't find the key item
}
Or if you want to work on the found item:
Item* item = 0;
for(int i = O; i LIMIT; ++i)
{
if (key == table[i])
{
item = &table[i];
break;
}
}
if (item)
{
// work on item-
}
There was another reason – does the following work on your Borland compiler?
for (int i = 0; int j = (i < LIMIT); ++i)
{
// ...
}
i = j;
While i stays in scope, j should go out of scope. This behaviour is a consequence of the decision to introduce run-time type identification in March ‘93 and allow declarations in the condition of if, switch, while and for.
Member constants
Hopefully, this decision will be more to your liking. Isn’t it annoying that you cannot have typed constants inside a class like you can everywhere else?
static const int size=42;
class X
{
public:
static const int mySize = 128; // illegal
private:
char buffer[mySize];
};
You had to muck about with enum and it didn’t always work. Well, we voted to allow the above example. A static integral data member may now have an initialiser inside the class. You still have to provide the static data member definition outside the class somewhere, and that cannot have an initialiser now, but that will probably get changed before we’re done – let us know what you think.
Templates
We resolved another long list of minor template issues, carrying on the work started in San Jose. We also added some extensions to make templates even more useful.
We added the ability to pass templates as arguments to other templates. This allows you to write container class templates and then write a container encapsulation class template for which you can specify different types of containers. An example would probably make this clearer:
template<class T>
class list;
template<class T>
class dyn_array;
template<class K,class V,template<class T> class C>
class map
{
C keys; // a C container of K keys
C values; // a C container of V values
// ...
};
map<g,string,list> mapl;
map<g,string,dyn_array> map2;
This allows more control over the mechanisms used by template classes and will become more important as the use of templates matures.
We also decided to allow some conversions to take place for arguments to template functions. Effectively, this will allow the compiler to perform trivial conversions in order to match a template function. For example:
template<Class T>
void funcl(T* p)
{
// don't know whether T
// is const or not!
}
template<Class T>
void func2(const T* p)
{
// we know T is const
// now, but we cannot
// call func2 with, for
// example, a 'char*'
// argument - it wouldn't
// match the const-ness
// of the parameter
}
This problem is now solved: you can declare func2 as above and you will be able to call it with a char* argument – the compiler will perform the ‘trivial’ conversion from char* to const char*.
The final extension we added was to allow member functions to be templates. This solves a problem with writing a safe pointer template class. Consider the following code:
class base { ... };
class derived : public base { };
derived* dpl = ... ;
base* bpl = dpl;
// conversion 'derived*' = 'base*'
template<Class T>
class ptr
{
T* p;
public:
ptr(const ptr & pp)
: p(pp.p) [ }
// ...
};
ptr<derived> dp2 = ... ;
ptr<base> bp2 = dp2; // illegal!
The problem is that there is no relationship between ptr<base> and ptr<derived> – they are just two different classes. Ideally, you want a constructor for ptr that takes something other than a T* but only those types that can be converted to T*. Member templates provide the solution like this:
template<class T>
class ptr
{
T* p;
public:
template<class U>
ptr(const ptr& pp)
: p(pp.p) { }
// ...
} ;
ptr<base> bp2 = dp2;
// valid: T == base,
// U == derived
The initialisation p(pp.p) will be valid only for U* that can be converted to T*, so the ptr constructor allows ‘normal’ pointer conversions.
We discussed a few more extensions for templates that will probably come up for a vote in Waterloo. These include template typedefs, te mplate name spaces and namespaces as template arguments. These would make templates more orthogonal by removing restrictions on what can be a template.
Core Language changes
It was decided to disallow const and volatile qualifiers on the top level of a reference declaration – the following is now ill-formed:
int i ;
int& const ir = i;
No one seemed to know what such a declaration should mean, so now you can’t write it!
It was decided that the left hand side of . or -> is evaluated, even when the right hand side is a static member. Previously the left hand side was only evaluated if the right hand side was a non-static member.
class example
{
public:
static void sf();
void f( ) ;
} ;
example* g();
g()->f(); // always calls g()
g()->sf(); // previously, did not call g(),now it does
This makes the language a bit more intuitive – it certainly needs it!
Library issues
Some minor changes were made to the proposed use of namespaces and exceptions within the library. Quite a few ‘editorial’ changes were agreed for the library section of the draft standard.
The main topic of interest for the library was “The Standard Template Library” which was described by its author, Alex Stepanov of Hewlett-Packard.
Although it was not discussed in committee – lack of time – there was a great deal of interest in this work as it would fill some of the holes in the library. STL contains various container classes, such as list, and associated iterators which are missing from the current draft standard.
It also provides a coherent framework for template classes which the draft standard library lacks. Hopefully, there will be a formal proposal to include this into the draft standard at the Waterloo meeting. In the meantime, I have signed up, with several others, to work with STL and report on what I find.
The next Casting Vote column will tell you what happened in Waterloo in July 1994.
Sean A. Corfield
I can be contacted by e-mail: Sean.Corfield@prqa.co.uk