Topic: Defect, missing info or correct definition


Author: "Emmanuel Deloget" <logout@free.fr>
Date: Mon, 4 Dec 2006 11:14:46 CST
Raw View
I am currently working on the library extension described in the TR1,
and I'm facing disturbing definitions that may or may not extend far
beyond their original meaning. Part of the problem is that when trying
to find the correct interpretation of the TR1 definition, I usually end
up with cases that I can't implement or that doesn't make much sense,
and the issue I want to describe here is one of them.

The TR1 requires reference_wrapper<> to inherit unary_function<> if the
wrapped type T inherit unary_function<> and binary_function<> is T
inherit binary_function<>. It also requires the implementor to
implement a weak result type which is either:
* the return type of the function/reference to a function/pointer to a
function/member function if T is one of these
* T::result_type if T defines it
* otherwise, result_type shall not be defined.

Now, it seems perfectly valid to wrap a class which inherit both
unary_function<> and binary_function<>, as the neither TR1 text nor the
next standard early draft text prohibits this. As a consequence,
reference_wrapper<T>::result_type can be quite difficult to define in
this case since it can be any of the following:
* T::result_type if it is defined
* T::unary_function::result_type
* T::binary_function::result_type

Pete Becker already told me that, in his meaning, the wrapped type
should not inherit both (on a recent comp.lang.c++ thread,
(http://groups.google.com/group/comp.lang.c++/browse_thread/thread/64ff14e9afefb1cc).
that simplifies the problem a lot, as I still don't foresee any legal
way to distinguish between the case were T::result_type is defined and
the case where T inherit the defintions of result_type from his parent
classes; but that's another problem). However, I still think that it
might be perfectly valid to define a wrapped type which inherit both
and provide two (or more) overload for operator(). In such case,
reference_wrapper<T>::result_type makes little sense, as the different
overloads might have different return types.

So here is the question: shall reference_wrapper<> handle such case?
If no, should the standard tells it explicitely?
If yes, how result_type should be defined? Should its definition be
extended?

Thanks for your patience,

-- Emmanuel Deloget, Artware

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Mon, 4 Dec 2006 16:09:34 CST
Raw View
Emmanuel Deloget wrote:
> The TR1 requires reference_wrapper<> to inherit unary_function<> if the
> wrapped type T inherit unary_function<> and binary_function<> is T
> inherit binary_function<>. It also requires the implementor to
> implement a weak result type which is either:
> * the return type of the function/reference to a function/pointer to a
> function/member function if T is one of these
> * T::result_type if T defines it
> * otherwise, result_type shall not be defined.
>
> Now, it seems perfectly valid to wrap a class which inherit both
> unary_function<> and binary_function<>, as the neither TR1 text nor the
> next standard early draft text prohibits this.

A class that inherits from both std::unary_function and
std::binary_function would have an ambiguously-named T::result_type. So
a program that tried to wrap an instance of one in a
reference_wrapper<> would simply fail to compile.

>As a consequence,
> reference_wrapper<T>::result_type can be quite difficult to define in
> this case since it can be any of the following:
> * T::result_type if it is defined
> * T::unary_function::result_type
> * T::binary_function::result_type

No, either T::result_type is defined or it is not. And if it defined,
it is always defined unambiguously in any well-formed program. So
whatever the type T::result_type names - is the type that
reference_wrapper has to use - and no other.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Peter Dimov" <pdimov@gmail.com>
Date: Mon, 4 Dec 2006 17:45:03 CST
Raw View
Emmanuel Deloget wrote:

> The TR1 requires reference_wrapper<> to inherit unary_function<> if the
> wrapped type T inherit unary_function<> and binary_function<> is T
> inherit binary_function<>. It also requires the implementor to
> implement a weak result type which is either:
> * the return type of the function/reference to a function/pointer to a
> function/member function if T is one of these
> * T::result_type if T defines it
> * otherwise, result_type shall not be defined.
>
> Now, it seems perfectly valid to wrap a class which inherit both
> unary_function<> and binary_function<>, as the neither TR1 text nor the
> next standard early draft text prohibits this. As a consequence,
> reference_wrapper<T>::result_type can be quite difficult to define in
> this case since it can be any of the following:
> * T::result_type if it is defined

This is correct.

> * T::unary_function::result_type
> * T::binary_function::result_type

These aren't. If T::result_type is defined to something else, it takes
precedence. TR1 doesn't say anything about reference_wrapper looking
into the base class's result_type. Just implement the letter of the
text.

- reference_wrapper<T> inherits from unary_function if T inherits from
unary_function,
- reference_wrapper<T> inherits from binary_function if T inherits from
binary_function,
- reference_wrapper<T>::result_type is defined to T::result_type iff T
has a result_type.

If a type F derives from both unary_function<X, R1> and
binary_function<Y, Z, R2> and has a nested result_type defined as R3,
you simply echo this in reference_wrapper<F> and let the user sort it
out.

If a type F derives from both bases but defines no result_type itself,
your SFINAE-based has_result_type predicate will report false (because
of the ambiguity) and you will again reproduce the traits of F
faithfully in reference_wrapper<F>, however little sense this would
make.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]