Re: Exception specifications unfortunate, and what about their future?
On Dec 10, 7:20 am, Gerhard Menzl <clcppm-pos...@this.is.invalid>
wrote:
Karl Uppiano wrote:
I think that depends on how statically checked exceptions are
ultimately implemented. You would have to prove to me that the set is
unbounded, and that there was no way to solve that.
The first proof is easy. In
template <typename T> class C
{
//...
};
the set of argument types for T is, by definition, unbounded.
That is untrue. T is bounded. The //... that you removed determines
the bounds of T. If we use a function f(x) on an x of type T in the
template, then T is bound to only those types for which f(T) is
defined. This is called an "implicit interface" in C++.
Similarly, if we had compile time exception specifications, then the
exception specifications on the member functions of C would limit what
types could be used for T.
So for some member
template <typename T>
class C {
f() throws() {
T o();
o.g();
}
};
Would not compile for a T that defines the default constructor, or T::g
() to throw.
Constraints are placed on T just as much as there are constraints with
run time polymorphic types. Templates are not special, they are just
compile time polymorphism.
Templates allow for easy copying without slicing, so the issue of the
exception specification of the copy constructor and assignment
operator comes up more than in run time polymorphic types, which only
occasionally implement the equivalent "clone" operation.
However, the issue of the exception specification is already
important. Sometimes you want a no throw guarantee from a copy
constructor. Sometimes it is ok to propagate them.
I think you were getting at the case where you want to propagate the
exception. There seem to be two ways to do this. Use the java route
and say you can always throw some class of exceptions that are
unchecked. Memory allocation errors should obviously be in this
category, and that would solve most copy constructor issues.
You could also provide a mechanism for doing type inference on the
exception specification like:
template<typename T>
void f() throws(auto) {
T o();
}
Then if the default constructor for T throws foo, f<T>() is specified
as throwing foo as well.
For more fine grained control, you could allow inference based on a
list of functions.
template<typename T>
void f() throws(T::T(), T::g(), T::operator=(const T&)) {
T o();
o.g();
T p();
p = o;
}
Note that if any of T::T(), T::g(), T::operator=(const T&) have *no*
exception specification, then we have two choices:
1. do type inference on T::T(), etc. This is probably not practical
given how many compilers can't do this kind of analysis outside of a
translation unit. This would be impossible for shared libraries.
2. Make f() unspecified. I think this is the most reasonable thing to
do. Then exception specs only come into play when you have them from
the bottom up, and are ignored
in cases involving legacy code.
The real problem is that for any of this to be useful, we have to
ditch the runtime checks. As long as those checks are there, exception
specs have more overhead than they are worth.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]