Brendon Costa wrote: > You as an author of a new template class "could" define it the other way. > > The issue here is that doing so restricts usage of the generic > component. In specific cases this may be desirable, but not for generic > components like STL containers or those in boost. For generic components > you want to make them as useful as possible. Even if at the time of > writing the container you do not foresee that throwing any type of > exception is a good idea, users may come up with some way of using it > that you just never thought about. > > I.e. I think the general philosophy is to define only what restrictions > are necessary to implement the template, not necessarily what we think > constitute good uses of the template at the time we created it.
I definately agree with your comments here (generic components should often allow their types to throw what they like), I'm just not sure how to achieve it any other way. Here's some ideas: 1) In many cases, templates can make a pretty good case for requiring no-throw for member functions of their type, such as destructors and move constructors. Currently, templates can't restrict exceptions when they should and when they shouldn't. With the warning, templates need to restrict exceptions when they should and when they shouldn't, (or be throw all, which requires an ugly downstream catch(...) ). Both aren't optimal, although preventing a legitimate thing is worse than allowing a wrong thing. 2) As in my last post, use template parameters to specify additional exception types. =================================== #include <iostream> class foo { public: void bar() throw(float) { throw float(5); } }; template <typename F> // or use concepts. class zug { public: template <typename E> void call_bar() throw(int, E) { f.bar(); throw int(3); } F f; }; int main() { zug<foo> zf; try { zf.call_bar<float>(); // here float is passed as an additional exception. } catch(int& caught) { std::cout << "caught an int" << std::endl; } catch(float& caught) { std::cout << "caught a float" << std::endl; } return 0; } =================================== output: caught a float =================================== The above works on code::blocks, which uses some form of GCC, and looks OK to me. Of course this only works for exactly one exception type. You'd have to wait for C++0X variadic templates (and hope you can throw them) if you need zero or more than one. It's also very verbose, a little cryptic, and nested templates could make variadic versions horrifically long. However it's a start. Brendon Costa wrote: > I had to go to lengths to provide > a "suppressions" system for EDoc++, simply because almost all code can > throw all sorts of exceptions i had never heard of before. A developer > "generally" is not interested in exceptions like: > __gnu_cxx::recursive_init. But after writing EDoc++ i found exceptions > like this turn up all over the place, though they should not occur in > normal operation... As for implicit exceptions that aren't manually thrown with a throw statement, eg: __gnu_cxx::recursive_init (http://www.cygwin.com/ml/cygwin-developers/2005-05/msg00019.html) or arithmetic exceptions (perhaps 1/0 etc) I would just suggest ignoring these. Eventually the compiler _may_ declare these exceptions per implicit op or remove the exceptions, but either way it's too difficult to manage manually. You could still specify those exceptions if you're really masochistic. There is something else to consider. If this project works reasonably well and perhaps becomes popular, it's not unreasonable to suggest some minor extensions to the C++ standard to help people code using it. For example: 1) allowing typedef'd function pointers and concept functions to have a throw specifier. 2) allowing: "void bar() throw(type_a, type_b, foo::throw);" or "..., foo())" or something whereby bar inherits foo's throw specifiers, which would mainly solve the above template problem. 3) extending 2 by giving the option of removing specific types, "void bar() throw(foo::throw, not int);" so that you can reduce the types thrown by catching them. I can think of some circumstances where this could be useful but I'm not sure if they're common enough to justify it. Which would then make rigid exception specifying easy enough to use everywhere. Ok I know I'm trying to fly before I can crawl here :) Just something to think on.