Topic: Overloading on nothrow
Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 12 Sep 2003 23:01:35 +0000 (UTC) Raw View
johnchx2@yahoo.com (johnchx) writes:
> Personally...I think that the interesting part of the idea is being
> able to ask the compiler, at compile time, whether a given function is
> guaranteed not to throw. The "overload-like" resolution seems to me
> to be an unnecessary complication. I'd be perfectly happy with an
> operator or even a traits class.
Interesting, sure. But useful? Worth the trouble? We've yet to see
a single compelling use case.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Fri, 12 Sep 2003 23:02:36 +0000 (UTC) Raw View
johnchx2@yahoo.com (johnchx) wrote in message news:<4fb4137d.0309082138.61d9ca42@posting.google.com>...
...
> template <class T>
> int foo(T& t)
> {
> return t.zoom();
> }
>
> template <class T>
> int bar(T& t)
> {
> try { return t.zoom(); }
> catch (...) { /* do something */ }
> }
>
> template <class T>
> int f(T& t)
> {
> return is_nothrow( foo(t) ) ? foo(t) : bar(t);
> }
It seems to me that
a) it would be more appropriate to use is_nothrow(foo<T>).
b) it would be more appropriate if is_nothrow() looked only at the
declaration of the function it is passed, and not at the actuall
implementation.
Getting back to the original issue, what might be a good idea is the
ability to specialize a template based upon the exception
specification for one of it's template arguments. That can be done
based entire upon the declaration of the function, which would be
consistent with current overload resolution. Overloading based upon
the actual implementation of a function is not a good idea.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: johnchx2@yahoo.com (johnchx)
Date: Sat, 20 Sep 2003 16:48:55 +0000 (UTC) Raw View
dave@boost-consulting.com (David Abrahams) wrote in message news:<uhe3iwu6i.fsf@boost-consulting.com>...
> johnchx2@yahoo.com (johnchx) writes:
>
> > Personally...I think that the interesting part of the idea is being
> > able to ask the compiler, at compile time, whether a given function is
> > guaranteed not to throw. The "overload-like" resolution seems to me
> > to be an unnecessary complication. I'd be perfectly happy with an
> > operator or even a traits class.
>
> Interesting, sure. But useful? Worth the trouble? We've yet to see
> a single compelling use case.
>
boost::has_nothrow_copy<T> ?
Wouldn't the as-yet-unspecified help from the compiler -- needed to
implement this and related type traits in a general fashion -- likely
look like a mechanism for asking the compiler whether a function (in
this case the copy-ctor) is guaranteed not to throw?
Maybe there's a distinction I'm missing.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Mon, 8 Sep 2003 16:45:30 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F31FF64.F697404A@iobox.com>...
> mvitalo wrote:
> > > > It would be nice to have a container class where the methods are
> > > > overloaded to throw or not, for example.
> > >
Is there some overwhelming reason why std::nothrow could not be used
here? It seems to me that overloading on an additional parameter of
type std::nothrow, coupled with an explicit empty exception
specification on the nothrow function, would pretty much get you what
you want, without any other changes to the language. This would be
self-documenting in the code and enfoceable by the compiler. And it
is an approach already demonstrated to work in the standard library.
Why invent a new solution if an appropriate one already exists?
What problem am I missing that such an approach would not solve?
Randy.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Mon, 8 Sep 2003 16:45:30 +0000 (UTC) Raw View
Bob Bell wrote:
> What's the point of overloading on nothrow if I can't call the nothrow
> version?
You're looking from the wrong point.
Overloading on nothrow is defined _only_ for templates. Compiler generates
_only_ _one_ specialization of f<SomeType>(): it will be either nothrow or
not.
> > In particular, overloading on nothrow allows us to propagate the nothrowness
> > to upper levels.
>
> I don't think you're getting my point. What is the real-world reason
> we need to make this change?
1. Suppose you have to write a function template:
2. And you call t.g() inside f():
3. And your implementation substantively depends on the fact whether t.g()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
throws. I.e. you have a bulk general case algorithm_1 (that has to cope with
^^^^^^^
exceptions) and an "optimal" algorithm_2 (which is free to be fast).
^^^^^^^^^^^^^^^^^^^^^^^^
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Tue, 9 Sep 2003 15:21:04 +0000 (UTC) Raw View
Randy Maddox wrote:
> Is there some overwhelming reason why std::nothrow could not be used
> here?
[snip]
> Why invent a new solution if an appropriate one already exists?
>
> What problem am I missing that such an approach would not solve?
Overloading on nothrow is the second step (actually, the word "overloading"
isn't well-chosen and is rather confusing w.r.t. the concept).
The first step is statically checked nothrow specifications and blocks.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Tue, 9 Sep 2003 15:21:04 +0000 (UTC) Raw View
[this is a repost]
Bob Bell wrote:
> What's the point of overloading on nothrow if I can't call the nothrow
> version?
You're looking from the wrong point.
Overloading on nothrow is defined _only_ for templates. Compiler generates
_only_ _one_ specialization of f<SomeType>(): it will be either nothrow or
not.
> > In particular, overloading on nothrow allows us to propagate the nothrowness
> > to upper levels.
>
> I don't think you're getting my point. What is the real-world reason
> we need to make this change?
1. Suppose you have to write a function template:
2. And you call t.g() inside f():
3. And your implementation substantively depends on the fact whether t.g()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
throws. I.e. you have a bulk general case algorithm_1 (that has to cope with
^^^^^^^
exceptions) and an "optimal" algorithm_2 (which is free to be fast).
^^^^^^^^^^^^^^^^^^^^^^^^
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: johnchx2@yahoo.com (johnchx)
Date: Thu, 11 Sep 2003 16:32:18 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote
> You're looking from the wrong point.
I've hesitated to wade into this thread, but I think Sergey has an
interesting idea which is in danger of getting lost because of a poor
(or at least confusing) choice of terminology. Let me try to
re-formulate what I believe he's getting at (with my apologies in
advance if I've misunderstood).
What it boils down to is the ability to do two things:
(1) Ask the compiler whether a particular function is guaranteed not
to throw an exception, and...
(2) call one function if the answer is "yes," and a different one if
the answer is "no".
Let's leave templates out of it for a moment, just to make the idea
clear:
int foo() { /* ... */ }
int bar() { /* ... */ }
int f() { return is_nothrow( foo() ) ? foo() : bar(); }
How would a compiler implement the hypothetical "operator
is_nothrow()"? Trivially, it could always return false...that's the
compiler's way of saying "I have no idea whether foo() might throw or
not."
Less trivially, it might look to whether the function is declared with
an empty exception specification (i.e. is it declared "throw()").
An even cleverer compiler could look into the actual implementation of
the function -- i.e. all the funtions *it* calls, to determine whether
that function really can't throw an exception. This is the level of
sophistication that Sergey seems to have in mind.
Now, let's re-introduce templates:
template <class T>
int foo(T& t)
{
return t.zoom();
}
template <class T>
int bar(T& t)
{
try { return t.zoom(); }
catch (...) { /* do something */ }
}
template <class T>
int f(T& t)
{
return is_nothrow( foo(t) ) ? foo(t) : bar(t);
}
In this case, the compiler needs to instantiate foo<T>(), resolving
all the dependent names (e.g. zoom), and determine whether the
resulting function is guaranteed not to throw. Based on this, f()
will either call foo(t) or bar(t).
Of course, if our hypothetical operator is_nothrow() yields a
compile-time constant (like sizeof()), we can use template
metaprogramming instead of the runtime selection operator. I'm also
taking for granted that the expression
is_nothrow( foo(t) )
does *not* actually call foo(t) (just as sizeof does not evaluate its
operand).
All this seems straightforward -- tricky to implement, perhaps, but
easy to understand. Where it gets a little confusing is when we want
to throw away the explicit invocation of "operator is_nothrow()."
That is, instead of using a runtime ?: or a compile-time
metaprogramming construct to select between foo() and bar(), we use a
new mechanism syntactically similar to overload resolution. (That is,
we intentionally create a name collisision and provide "smart" rules
for the compiler to resolve the collision...which is what overload
resolution really does.)
So, for starters, instead of foo() and bar(), we have just one name
with two implementations:
template < class T >
int foobar(T& t) is_nothrow // note new magic keyword :-)
{
return t.zoom();
}
template < class T >
int foobar(T& t)
{
try {
return t.zoom();
}
catch (...) { /* do something */ }
}
template < class T >
int f(T& t)
{
return foobar(t);
}
When the compiler is called upon to instantiate f(), it tries to bind
the name foobar. It finds the two templates, which are identical from
the point of view of traditional overload resolution (therefore an
error). However, the compiler can resolve the ambiguity by noticing
that one of the possible bindings is associated with the new magic
keyword is_nothrow and the other is not. Under these specific
conditions, a rule applies: instantiate the template declared
is_nothrow and ascertain whether it is guaranteed not to throw. If
the compiler can obtain that guarantee, the is_nothrow version is
selected. If the compiler cannot obtain that guarantee for any
reason, the non-is_nothrow version is prefered.
Again, this isn't exactly overload resolution in the traditional
sense...but there's a rough analogy.
Personally...I think that the interesting part of the idea is being
able to ask the compiler, at compile time, whether a given function is
guaranteed not to throw. The "overload-like" resolution seems to me
to be an unnecessary complication. I'd be perfectly happy with an
operator or even a traits class.
Again, my apologies to Sergey if I've misunderstood or omitted
anything.
--John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Fri, 22 Aug 2003 16:41:57 +0000 (UTC) Raw View
[I've sent this reply on Fri, 15 Aug 2003 but it seems like it was lost]
James Kuyper wrote:
> The way C++ currently works, all you need to determine which overload
> of f() to use is the declaration of f(), and the declarations of the
> types which are passed to it as arguments.
Not, really.
I propose to overload a _template_ f(). And even in current C++ you
have to do a huge amount of work in order to figure out what exactly will be
the result of f<>((SomeType)st) call: specializations, traits and so on must
be taken into the consideration.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Bob Bell <belvis@pacbell.net>
Date: 13 Aug 2003 09:41:18 -0400 Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F31FF64.F697404A@iobox.com>...
[snip]
> 4. Then you define two versions of f() overloaded on nothrow:
>
> template<class T> void f(T t)
> {
> algorithm_1
> }
>
> and
>
> template<class T> void f(T t) nothrow
> {
> algorithm_2
> }
SomeType foo;
f(foo);
Which f does the compiler choose?
[snip]
> 6. For example:
>
> template <class T>
> class StrictlyRelatedPair {
> T a;
> T b;
>
> // general case with strong guarantee
> StrictlyRelatedPair& operator=(const StrictlyRelatedPair& other)
> {
> StrictlyRelatedPair tmp(other);
> this->swap(tmp);
> return *this;
> }
>
> // lightweight version in the case of T& operator=(const T&) nothrow
> StrictlyRelatedPair& operator=(const StrictlyRelatedPair& other) nothrow
> {
> a=other.a;
> b=other.b;
> return *this;
> }
> };
StrictlyRelatedPair<Foo, Bar> x, y;
x = y;
Which operator= does the compiler choose?
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Thu, 14 Aug 2003 01:29:42 GMT Raw View
Bob Bell wrote:
> > 4. Then you define two versions of f() overloaded on nothrow:
> >
> > template<class T> void f(T t)
> > {
> > algorithm_1
> > }
> >
> > and
> >
> > template<class T> void f(T t) nothrow
> > {
> > algorithm_2
> > }
>
> SomeType foo;
>
> f(foo);
>
> Which f does the compiler choose?
>
It depends on the signature of SomeType::g(), i.e.
void SomeType::g();
or
void SomeType::g() nothrow;
Please note that non-template SomeType shall have only one g() which is
definitely nothrow or not, while template class SomeType (and/or template
SomeType::g()) is allowed to have both versions overloaded on nothrow.
PS The statically checked nothrow specification was described by me several
times. For example
http://groups.google.com/groups?ie=UTF-8&oe=UTF-8&selm=3A5887F9.6CFCFFD7%40iobox.com
-----------------------------------8<-----------------------------------
IMHO compiler needs exactly one answer: whether function can throw. It doesn't
matter _what_ it gonna throw. So it seems like a nothrow keyword would be
much more useful. Consider:
1.
// f can throw what it wants
void f()
{
// ...
}
2.
// f is not allowed to throw (checked at compile time)
void f() nothrow
{
// ...
}
3.
void f()
{
// ...
nothrow { // you can't throw in this scope (checked at compile time)
// ...
}
// ...
}
IMHO with nothrow clauses and blocks one can easily create exception-safe
code, which is a nightmare in current C++.
-----------------------------------8<-----------------------------------
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Bob Bell <belvis@pacbell.net>
Date: 14 Aug 2003 08:23:37 -0400 Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F3A4EB2.6BBE9FA3@iobox.com>...
> Bob Bell wrote:
> > > 4. Then you define two versions of f() overloaded on nothrow:
> > >
> > > template<class T> void f(T t)
> > > {
> > > algorithm_1
> > > }
> > >
> > > and
> > >
> > > template<class T> void f(T t) nothrow
> > > {
> > > algorithm_2
> > > }
> >
> > SomeType foo;
> >
> > f(foo);
> >
> > Which f does the compiler choose?
> >
> It depends on the signature of SomeType::g(), i.e.
>
> void SomeType::g();
>
> or
>
> void SomeType::g() nothrow;
What's so special about SomeType::g()? In particular, as the one who
wants to call f with a SomeType object, I know there are two functions
available:
template<class T> void f(T t);
template<class T> void f(T t) nothrow;
Why does SomeType::g() come into it? How am I to know (looking at
these declarations of f()) that SomeType::g() is the determining
function and not SomeType::h()?
If SomeType::g() is the special function (presumably because it's
being used somewhere inside f()), what happens if f's implementation
changes in the future and now calls SomeType::h() instead/as well? If
SomeType::g() is nothrow, but SomeType::h() isn't for some reason,
then the next build will silently switch from the non throwing f() to
the throwing f(). This kind of silent change seems pretty bad.
(Although if the throw/nothrow thing is checked statically, as you
suggest later, maybe it's not a silent change. But static checking has
its own problems, from what I understand.)
In any case, if the compiler makes its choice based on the set of
SomeType functions that are called within f(), that means that the
overloading won't work unless the compiler has access to the
implementation of f(). This may be a problem with exported templates,
but I'm not an implementer so I'm not sure. (Later in your post you
rule out overloading on nothrow with non-template functions, if I read
correctly, so only template functions need to be considered.)
Unless I'm missing something (which happens more often than I'd like
to admit), it seems that this kind of "overload on nothrow" is very
different from ordinary overloading. With ordinary overloading, the
function signature of the overloaded function is all you need to see
to predict which overload will be called with a given set of
arguments. With overload on nothrow, you need to know not only the
function signature, but _how_ those types are used within the function
to predict which overload will be selected. This means that the
interface (in terms of which function gets called) has a dependency on
the implementation, and seems like a loss of encapsulation.
I kind of like the idea of overloading on nothrow, but this seems to
be a big problem, and anyway, others have asked for examples of
problems that can be solved with it, and no convincing answers have
been given.
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Fri, 15 Aug 2003 04:34:33 GMT Raw View
Bob Bell wrote:
> What's so special about SomeType::g()?
>
It seems like you haven't read my message. The corresponding snippet is:
-----------------------------------8<-----------------------------------
2. And you call t.g() inside f():
template<class T> void f(T t)
{
// ...
t.g();
// ...
}
3. And your implementation substantively depends on the fact whether t.g()
throws. I.e. you have a bulk general case algorithm_1 (that has to cope with
exceptions) and an "optimal" algorithm_2 (which is free to be fast).
-----------------------------------8<-----------------------------------
> If SomeType::g() is the special function (presumably because it's
> being used somewhere inside f()), what happens if f's implementation
> changes in the future and now calls SomeType::h() instead/as well?
>
1. Compiler sees two versions of f<>() overloaded on nothrow.
2. It trys to instantiate f<SomeType>() specialization:
2.1. It trys to instantiate f<SomeType>() nothrow version. If the body of
f<SomeType>() specialization throws it will try the second version:
2.2. It trys to instantiate f<SomeType>() plain version.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: Fri, 15 Aug 2003 12:16:21 GMT Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F3A4EB2.6BBE9FA3@iobox.com>...
> Bob Bell wrote:
> > > 4. Then you define two versions of f() overloaded on nothrow:
> > >
> > > template<class T> void f(T t)
> > > {
> > > algorithm_1
> > > }
> > >
> > > and
> > >
> > > template<class T> void f(T t) nothrow
> > > {
> > > algorithm_2
> > > }
> >
> > SomeType foo;
> >
> > f(foo);
> >
> > Which f does the compiler choose?
> >
> It depends on the signature of SomeType::g(), i.e.
>
> void SomeType::g();
>
> or
>
> void SomeType::g() nothrow;
The way C++ currently works, all you need to determine which overload
of f() to use is the declaration of f(), and the declarations of the
types which are passed to it as arguments. With your proposed change,
it would also need to examine the actual body of f(), to find out
whether, in the current context, it invokes any functions that aren't
nothrow fuctions. That doesn't sound like good idea to me.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Fri, 22 Aug 2003 16:41:57 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F3B8E09.51D5E113@iobox.com>...
> Bob Bell wrote:
> > What's so special about SomeType::g()?
> >
> It seems like you haven't read my message. The corresponding snippet is:
> -----------------------------------8<-----------------------------------
> 2. And you call t.g() inside f():
>
> template<class T> void f(T t)
> {
> // ...
> t.g();
> // ...
> }
>
> 3. And your implementation substantively depends on the fact whether t.g()
> throws. I.e. you have a bulk general case algorithm_1 (that has to cope with
> exceptions) and an "optimal" algorithm_2 (which is free to be fast).
> -----------------------------------8<-----------------------------------
It seems you missed my point. From the interface of f<T>(), there is
no way for me to deduce that SomeType::g() must be nothrow in order
for the overload resolution to pick the non-throwing version of
f<T>(). The interface may be all I have, if the f<T>() is an exported
template.
> > If SomeType::g() is the special function (presumably because it's
> > being used somewhere inside f()), what happens if f's implementation
> > changes in the future and now calls SomeType::h() instead/as well?
> >
> 1. Compiler sees two versions of f<>() overloaded on nothrow.
>
> 2. It trys to instantiate f<SomeType>() specialization:
>
> 2.1. It trys to instantiate f<SomeType>() nothrow version. If the body of
> f<SomeType>() specialization throws it will try the second version:
>
> 2.2. It trys to instantiate f<SomeType>() plain version.
You also seem to have missed my point about silent changes to the
meaning of my code, as well as the point about this being a new kind
of overloading that depends on the implementation of the overloaded
function.
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Mon, 25 Aug 2003 16:17:10 +0000 (UTC) Raw View
Bob Bell wrote:
> It seems you missed my point. From the interface of f<T>(), there is
> no way for me to deduce that SomeType::g() must be nothrow in order
> for the overload resolution to pick the non-throwing version of
> f<T>(). The interface may be all I have, if the f<T>() is an exported
> template.
>
Well, it doesn't really matter whether SomeType::g() throws. The overloading
on nothrow is a powerful feature. And just like every powerful feature it can
be _mis_used. In particular, your example is about how _not_ to use it.
Sometimes you have a template<class T> YourClass<T> and you know that
YourClass<SomeType> "doesn't throw" if corresponding methods of SomeType don't
throw.
Via the overloading on nothrow you can tell your users (actually, you tell it
to the C++ type system) that YourClass<SomeType>::f() is a nothrow function.
Without this feature _all_ specializations of YourClass will be "canthrow"
(from the C++ type system POV) despite the fact that some of them can't really
throw and this can be unambiguously deduced at compile time.
I don't tell that the overloading on nothrow can't be misused. I does tell
that it improves C++ type system when used correctly (and it's not so hard to
get it rigth).
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Sun, 31 Aug 2003 01:40:30 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F474CD6.93B8F692@iobox.com>...
> Bob Bell wrote:
> > It seems you missed my point. From the interface of f<T>(), there is
> > no way for me to deduce that SomeType::g() must be nothrow in order
> > for the overload resolution to pick the non-throwing version of
> > f<T>(). The interface may be all I have, if the f<T>() is an exported
> > template.
> >
> Well, it doesn't really matter whether SomeType::g() throws. The overloading
> on nothrow is a powerful feature. And just like every powerful feature it can
> be _mis_used. In particular, your example is about how _not_ to use it.
This isn't my example, it's yours; I just asked a question about it.
You were the one that said that for overload resolution to pick the
nonthrowing f<T>, T::g() must be nothrow. How can I, as someone who
wants to use f<T>, know that?
Unless I can read the source code (which I may not be able to do), I
can't know that. Which means that I don't know how to write SomeType
so that instantiating f<SomeType> will pick the nothrow version. So
how can I use this feature?
Overload on nothrow changes the meaning of overloading significantly:
it means that overload resolution would depend on the implementation
of the overloaded functions. I don't see this as an improvement at
all. I see it as creating inappropriate dependencies between my code
and the implementations of the functions I call -- as demonstrated by
your example, where the precise version of f<T> I call depends on how
f<T> is implemented.
> Sometimes you have a template<class T> YourClass<T> and you know that
> YourClass<SomeType> "doesn't throw" if corresponding methods of SomeType don't
> throw.
Note that this guideline won't help the user of f<T> in your example.
> Via the overloading on nothrow you can tell your users (actually, you tell it
> to the C++ type system) that YourClass<SomeType>::f() is a nothrow function.
> Without this feature _all_ specializations of YourClass will be "canthrow"
> (from the C++ type system POV) despite the fact that some of them can't really
> throw and this can be unambiguously deduced at compile time.
>
> I don't tell that the overloading on nothrow can't be misused. I does tell
> that it improves C++ type system when used correctly (and it's not so hard to
> get it rigth).
I remain unconvinced. I haven't seen any serious discussion of the
problems for which overload on nothrow is a solution. What is the
problem? How often does it come up in real code? What are the
workarounds, if any, and how error-prone are they? What side-effects
does the proposed solution have (e.g, how does it relate to name
lookup)? Given that the changes to overload resolution are so
significant (especially considering the problems it introduces), I
would expect correspondingly significant answers to these questions,
but so far I haven't seen any.
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Sun, 31 Aug 2003 01:40:30 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message
news:<3F474CD6.93B8F692@iobox.com>...
> Bob Bell wrote:
> > It seems you missed my point. From the interface of f<T>(), there
is
> > no way for me to deduce that SomeType::g() must be nothrow in
order
> > for the overload resolution to pick the non-throwing version of
> > f<T>(). The interface may be all I have, if the f<T>() is an
exported
> > template.
> >
> Well, it doesn't really matter whether SomeType::g() throws.
The overloading
> on nothrow is a powerful feature. And just like every powerful
feature it can
> be _mis_used. In particular, your example is about how _not_ to use
it.
It wasn't my example, it was yours. You gave the example of f<T>()'s
overload resolution depending on whether or not T::g() throws. My
question is, how can I know, seeing the _declaration_ of f<T>(), that
T::g() is the member of T that discriminates between throwing and
non-throwing f<T>()?
Of course, the answer is I can't know that. Nothing about the
declaration of f<T>() tells me that T::g() is the discriminating
member. The only way I can tell is if I can look at the _definition_
of f<T>(), which I may not be able to see (e.g., if the f<T>() is an
exported template).
Also, this situation is quite different from today's use of templates.
With today's templates, if I try to call f<T>(), and internally f<T>()
calls T::g(), and there is no T::g(), I get a compiler error. Either
it compiles, or it doesn't, and if it compiles, the function that gets
called is determined wholly by the interface of the available
f<T>()'s. The fact that T::g() is called does not play any part in
_which_ f<T>() gets called. You are proposing to change that, and I
think that's a mistake.
> Sometimes you have a template<class T> YourClass<T> and you
know that
> YourClass<SomeType> "doesn't throw" if corresponding methods of
SomeType don't
> throw.
Note that this guideline wouldn't have helped the programmer who wants
to call f<T>() above.
> Via the overloading on nothrow you can tell your users
(actually, you tell it
> to the C++ type system) that YourClass<SomeType>::f() is a nothrow
function.
> Without this feature _all_ specializations of YourClass will be
"canthrow"
> (from the C++ type system POV) despite the fact that some of them
can't really
> throw and this can be unambiguously deduced at compile time.
I understand what you want, but it doesn't seem to be as simple as you
think. Consider this example:
template<typename T>
void F() nothrow
{
// ...
Foo();
// ...
}
template<typename T>
void F()
{
// ...
Foo();
// ...
}
Suppose no operation of X throws any exception, and I call
f<X>();
It seems to me that which F<T>() gets called now depends on whether or
not Foo() throws. Do I need to mark Foo(), an ordinary function, as
throwing or non-throwing? I'm guessing yes.
Consider this example:
template<typename T>
void F() nothrow
{
try {
T t;
t.foo();
}
catch (...) {
}
}
template<typename T>
void F()
{
T t;
t.foo();
}
F<X>();
Here it doesn't matter whether X throws or not (either function
works), so which overload with the compiler pick? More importantly,
how does it make the choice?
How about this example:
template<typename T>
void F() nothrow
{
try {
T t;
t.foo();
}
catch (Bar&) {
}
}
template<typename T>
void F()
{
T t;
t.foo();
}
F<X>();
Now the compiler's choice is harder: as long as X throws only Bar
exceptions, or exceptions derived from Bar, the compiler can pick the
nothrow function. But in general, it's not possible to determine at
compile time what exceptions a function might throw.
You might say that that is a "mis-use" of overload on nothrow, but
that doesn't change the validity of the questions; even if you don't
like this use of overload on nothrow, the compiler will still have to
do something if it sees code like this. So what should it do?
> I don't tell that the overloading on nothrow can't be misused.
I does tell
> that it improves C++ type system when used correctly (and it's not
so hard to
> get it rigth).
I don't see this as affecting the type system at all. There are still
lots of unanswered questions. How does this feature interact with
other overloads and specializations? How does this feature interact
with name lookup? How often does the problem that overload on nothrow
solves come up in real code? For real code where this is a problem,
what are the workarounds? Are these workarounds error-prone, or do
they have other disadvantages? What are the disadvantages of overload
on nothrow and how do they compare to the workarounds? How should this
feature behave when the compiler can't determine if a function is
actually nothrow or not? What happens when the compiler gets it wrong
(in particular, when a function which should be nothrow actually
throws an exception)?
For myself, I'm not convinced this is a problem worth solving; I've
never known it to be a problem with any code I've written. The
disadvantages seem to outweigh the advantages, so at this point, I say
overload on nothrow is a mistake C++ should avoid making.
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Sun, 31 Aug 2003 18:50:44 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F474CD6.93B8F692@iobox.com>...
> Bob Bell wrote:
> > It seems you missed my point. From the interface of f<T>(), there is
> > no way for me to deduce that SomeType::g() must be nothrow in order
> > for the overload resolution to pick the non-throwing version of
> > f<T>(). The interface may be all I have, if the f<T>() is an exported
> > template.
> >
> Well, it doesn't really matter whether SomeType::g() throws. The overloading
> on nothrow is a powerful feature. And just like every powerful feature it can
> be _mis_used. In particular, your example is about how _not_ to use it.
It wasn't my example, it was yours. You gave the example of f<T>()'s
overload resolution depending on whether or not T::g() throws. My
question is, how can I know, seeing the _declaration_ of f<T>(), that
T::g() is the member of T that discriminates between throwing and
non-throwing f<T>()?
Of course, the answer is I can't know that. Nothing about the
declaration of f<T>() tells me that T::g() is the discriminating
member. The only way I can tell is if I can look at the _definition_
of f<T>(), which I may not be able to see (e.g., if the f<T>() is an
exported template).
Also, this situation is quite different from today's use of templates.
With today's templates, if I try to call f<T>(), and internally f<T>()
calls T::g(), and there is no T::g(), I get a compiler error. Either
it compiles, or it doesn't, and if it compiles, the function that gets
called is determined wholly by the interface of the available
f<T>()'s. The fact that T::g() is called does not play any part in
_which_ f<T>() gets called. You are proposing to change that, and I
think that's a mistake.
> Sometimes you have a template<class T> YourClass<T> and you know that
> YourClass<SomeType> "doesn't throw" if corresponding methods of SomeType don't
> throw.
Note that this guideline wouldn't have helped the programmer who wants
to call f<T>() above.
> Via the overloading on nothrow you can tell your users (actually, you tell it
> to the C++ type system) that YourClass<SomeType>::f() is a nothrow function.
> Without this feature _all_ specializations of YourClass will be "canthrow"
> (from the C++ type system POV) despite the fact that some of them can't really
> throw and this can be unambiguously deduced at compile time.
I understand what you want, but it doesn't seem to be as simple as you
think. Consider this example:
template<typename T>
void F() nothrow
{
// ...
Foo();
// ...
}
template<typename T>
void F()
{
// ...
Foo();
// ...
}
Suppose no operation of X throws any exception, and I call
f<X>();
It seems to me that which F<T>() gets called now depends on whether or
not Foo() throws. Do I need to mark Foo(), an ordinary function, as
throwing or non-throwing? I'm guessing yes.
Consider this example:
template<typename T>
void F() nothrow
{
try {
T t;
t.foo();
}
catch (...) {
}
}
template<typename T>
void F()
{
T t;
t.foo();
}
F<X>();
Here it doesn't matter whether X throws or not (either function
works), so which overload with the compiler pick? More importantly,
how does it make the choice?
How about this example:
template<typename T>
void F() nothrow
{
try {
T t;
t.foo();
}
catch (Bar&) {
}
}
template<typename T>
void F()
{
T t;
t.foo();
}
F<X>();
Now the compiler's choice is harder: as long as X throws only Bar
exceptions, or exceptions derived from Bar, the compiler can pick the
nothrow function. But in general, it's not possible to determine at
compile time what exceptions a function might throw.
You might say that that is a "mis-use" of overload on nothrow, but
that doesn't change the validity of the questions; even if you don't
like this use of overload on nothrow, the compiler will still have to
do something if it sees code like this. So what should it do?
> I don't tell that the overloading on nothrow can't be misused. I does tell
> that it improves C++ type system when used correctly (and it's not so hard to
> get it rigth).
I don't see this as affecting the type system at all. There are still
lots of unanswered questions. How does this feature interact with
other overloads and specializations? How does this feature interact
with name lookup? How often does the problem that this feature solves
come up in real code? For real code where this is a problem, what are
the workarounds? Are these workarounds error-prone, or do they have
other disadvantages? What are the disadvantages of overload on nothrow
and how do they compare to the workarounds? How should this feature
behave when the compiler can't determine if a function is actually
nothrow or not? What happens when the compiler gets it wrong (in
particular, when a function which should be nothrow actually throws an
exception)?
For myself, I'm not convinced this is a problem worth solving; I've
never known it to be a problem with any code I've written. The
disadvantages seem to outweigh the advantages, so at this point,
overload on nothrow is a mistake C++ should avoid making.
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Mon, 1 Sep 2003 15:36:06 +0000 (UTC) Raw View
Bob Bell wrote:
> This isn't my example, it's yours; I just asked a question about it.
> You were the one that said that for overload resolution to pick the
> nonthrowing f<T>, T::g() must be nothrow. How can I, as someone who
> wants to use f<T>, know that?
>
Well, _why_ do you want to know whether f<T> is a nothrow function? That's
the point. The question about the T::g() -- is the second question (sometimes
you don't want to know about the T::g() at all).
Once more: with certain Ts f<T> never throws (but you can't declare it to be
nothrow because with others it does). Overloading on nothrow allows us to
explicitly tell this to C++ type system (see below, please).
> I remain unconvinced. I haven't seen any serious discussion of the
> problems for which overload on nothrow is a solution. What is the
> problem?
The problem is the cooperation of templates and exceptions.
In particular, overloading on nothrow allows us to propagate the nothrowness
to upper levels.
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Mon, 1 Sep 2003 15:36:07 +0000 (UTC) Raw View
Bob Bell wrote:
> It wasn't my example, it was yours. You gave the example of f<T>()'s
> overload resolution depending on whether or not T::g() throws. My
> question is, how can I know, seeing the _declaration_ of f<T>(), that
> T::g() is the member of T that discriminates between throwing and
> non-throwing f<T>()?
There is no intent to allow you to get this information from _declaration_.
Those f... manuals are written to be read :)
You read the manual and notice that: "Please note, that our f<T> doesn't
throw if T is ... So we've overloaded it on nothrow." That's the point.
In particular, you can use a nothrow block to get a compilation error if
something goes wrong:
void h()
{
// ...
nothrow {
f<int>();
}
// ...
}
> Of course, the answer is I can't know that. Nothing about the
> declaration of f<T>() tells me that T::g() is the discriminating
> member. The only way I can tell is if I can look at the _definition_
> of f<T>(), which I may not be able to see (e.g., if the f<T>() is an
> exported template).
You can laugh but documentation is much handier in addressing these kinds of
issues :) And moreover you _must_ be able to see the documentation.
> Also, this situation is quite different from today's use of templates.
Yes, and today's situation w.r.t. templates is nightmare :(
> With today's templates, if I try to call f<T>(), and internally f<T>()
> calls T::g(), and there is no T::g(), I get a compiler error. Either
> it compiles, or it doesn't, and if it compiles, the function that gets
> called is determined wholly by the interface of the available
> f<T>()'s.
The sad truth is that today's f<>() is always marked as canthrow: "You can
have any exception specification as long as it's canthrow."
> I understand what you want, but it doesn't seem to be as simple as you
> think. Consider this example:
>
> template<typename T>
> void F() nothrow
> {
> // ...
> Foo();
> // ...
> }
>
> template<typename T>
> void F()
> {
> // ...
> Foo();
> // ...
> }
>
> Suppose no operation of X throws any exception, and I call
>
> f<X>();
>
> It seems to me that which F<T>() gets called now depends on whether or
> not Foo() throws.
Not exact. If the Foo() call doesn't depend on the T template parameter and
Foo() has canthrow specification you will not be able to overload on nothrow:
compiler will tell you that F<>() has canthrow specification.
> Do I need to mark Foo(), an ordinary function, as
> throwing or non-throwing? I'm guessing yes.
Yes, you're right: it's supposed that every function will have statically
checked exception specification :) But it's quite irrelevant to the point
above.
> Consider this example:
>
> template<typename T>
> void F() nothrow
> {
> try {
> T t;
>
> t.foo();
> }
> catch (...) {
> }
> }
>
I see no trouble here: seeing the definition above compiler can deduce that
all specializations of this F's body can't throw so there is only one F - this
one; no overloading on nothrow is allowed.
> template<typename T>
> void F()
> {
> T t;
>
> t.foo();
> }
>
So this definition is a comlipe time error.
> How about this example:
The actual issue is whether the following code is well-formed:
void f(); // i.e. f can throw
void g() nothrow
{
try { f(); }
catch(Bar&) {}
}
No, it isn't. If you know, that only Bar exceptions can be thrown by f() let's
help to compiler:
void g() nothrow
{
try { f(); }
catch(Bar&) {}
catch(...) { assert(false, "Fire Bob, please!"); }
}
Now the code is well-formed. And we've just defined a nothow g() function.
>
> template<typename T>
> void F() nothrow
> {
> try {
> T t;
>
> t.foo();
> }
> catch (Bar&) {
> }
> }
>
And now you know the answer: the definition above is not well-formed. Period.
> template<typename T>
> void F()
> {
> T t;
>
> t.foo();
> }
>
> F<X>();
>
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Wed, 3 Sep 2003 05:25:31 +0000 (UTC) Raw View
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message news:<3F51F603.99CAAE31@iobox.com>...
> Bob Bell wrote:
> > This isn't my example, it's yours; I just asked a question about it.
> > You were the one that said that for overload resolution to pick the
> > nonthrowing f<T>, T::g() must be nothrow. How can I, as someone who
> > wants to use f<T>, know that?
> >
> Well, _why_ do you want to know whether f<T> is a nothrow function? That's
> the point.
What's the point of overloading on nothrow if I can't call the nothrow
version? To call the nothrow version with my type Foo, I need to know
what Foo operations must be nothrow in order to call f<T>(). In the
example you gave, it's impossible to tell.
> > I remain unconvinced. I haven't seen any serious discussion of the
> > problems for which overload on nothrow is a solution. What is the
> > problem?
> The problem is the cooperation of templates and exceptions.
> In particular, overloading on nothrow allows us to propagate the nothrowness
> to upper levels.
I don't think you're getting my point. What is the real-world reason
we need to make this change? "Because it lets us do x, y and z" is not
an answer; an answer would tell why we can't do without x, y and z.
Why can't we do without propagating nothrowness to upper levels?
Bob
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Sergey P. Derevyago" <non-existent@iobox.com>
Date: Thu, 07 Aug 2003 16:29:57 GMT Raw View
mvitalo wrote:
> > > It would be nice to have a container class where the methods are
> > > overloaded to throw or not, for example.
> >
> > But I don't understand how you arrive here from the foregoing. How
> > would having such overloaded methods be useful (if it's even
> > possible)?
>
> Having a container type that had methods overloaded on "nothrow" could
> allow me to use the same container in kernel and user space components.
>
Sorry, you missed the point.
1. Suppose you have to write a function template:
template<class T> void f(T t)
{
// ...
}
2. And you call t.g() inside f():
template<class T> void f(T t)
{
// ...
t.g();
// ...
}
3. And your implementation substantively depends on the fact whether t.g()
throws. I.e. you have a bulk general case algorithm_1 (that has to cope with
exceptions) and an "optimal" algorithm_2 (which is free to be fast).
4. Then you define two versions of f() overloaded on nothrow:
template<class T> void f(T t)
{
algorithm_1
}
and
template<class T> void f(T t) nothrow
{
algorithm_2
}
5. Well, that's all: say compiler can pick algorithm_1 for f<string>() and
algorithm_2 for f<int>().
6. For example:
template <class T>
class StrictlyRelatedPair {
T a;
T b;
// general case with strong guarantee
StrictlyRelatedPair& operator=(const StrictlyRelatedPair& other)
{
StrictlyRelatedPair tmp(other);
this->swap(tmp);
return *this;
}
// lightweight version in the case of T& operator=(const T&) nothrow
StrictlyRelatedPair& operator=(const StrictlyRelatedPair& other) nothrow
{
a=other.a;
b=other.b;
return *this;
}
};
--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]