Topic: Defect report (FCD): result_of precondition is nonsense
Author: David Krauss <potswa@gmail.com>
Date: Wed, 15 Sep 2010 23:05:17 CST Raw View
(Already sent to Alisdair Meredith.)
>From N3126 p.532 (20.7.6.6 table 53):
template <class Fn, class... ArgTypes> struct
result_of<Fn(ArgTypes...)>;
Fn shall be a function object type (20.8), reference to function, or
reference to function object type. The expression
decltype(declval<Fn>() (declval<ArgTypes>()...)) shall be well formed.
The member typedef type shall name the type decltype(declval<Fn>()
(declval<ArgTypes>()...))
----- end quote
Fn is the return type, not the function object type. Fn(ArgTypes...)
is *a* function type, namely a C-style function. But a functor type
won't even match this partial specialization. If my memory serves,
Boost Bind sometimes uses <Fn(ArgTypes...)> with a function object
type as Fn, but that is a means of pretty-printing error messages more
than anything else. It could just as well use <Fn, ArgTypes...>.
Perhaps the declaration was stated as such to create names for use in
the other columns of the table. However, there is no way to know how
all specializations (and some may be user-supplied) acquire the
argument types from the function object type. And that may not even be
necessary: for example, a partial specialization for
std::unary_function could simply say "typedef result_type type;" For
that matter, "typedef Fn type;" would seem to suffice in place of the
given text. The current text is clearly an overspecification.
Recommended change: Don't specify a partial specialization. (In my
opinion, the standard should never specify partial specializations
anyway!)
template <class Fn> struct result_of;
Fn shall be a function object type (20.8), reference to function, or
reference to function object type.
The member typedef type shall name the type of a function call
expression (5.2.2, 13.3.1.1) with Fn as the type of the postfix-
expression. If the type of such an expression is not determined by Fn,
the type of type is unspecified.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Thu, 16 Sep 2010 11:37:47 CST Raw View
On Sep 16, 7:05 am, David Krauss <pot...@gmail.com> wrote:
> >From N3126 p.532 (20.7.6.6 table 53):
>
> template <class Fn, class... ArgTypes> struct
> result_of<Fn(ArgTypes...)>;
>
> Fn shall be a function object type (20.8), reference to function, or
> reference to function object type. The expression
> decltype(declval<Fn>() (declval<ArgTypes>()...)) shall be well formed.
>
> The member typedef type shall name the type decltype(declval<Fn>()
> (declval<ArgTypes>()...))
>
> ----- end quote
>
> Fn is the return type, not the function object type.
No, this is an often occurring misconception of the
meaning of this parameter in the specialization of
result_of.
> Fn(ArgTypes...)
> is *a* function type, namely a C-style function. But a functor type
> won't even match this partial specialization.
If you have a look at the example shown at the end of 20.7
of N3126 you will notice that this generalization makes
sense:
typedef bool (&PF1)();
typedef short (*PF2)(long);
struct S {
operator PF2() const;
double operator()(char, int&);
};
the following assertions will hold:
static_assert(std::is_same<std::result_of<S(int)>::type,
short>::value, "Error!");
static_assert(std::is_same<std::result_of<S&(unsigned char,
int&)>::type, double>::value, "Error!");
static_assert(std::is_same<std::result_of<PF1()>::type, bool>::value,
"Error!");
Obviously, in neither of the first two examples, S or S& is the
return type, but they describe the "function object type" (or
reference thereof) where we would like to extract the return
type from given a particular set of arguments. Note also the
usage of the function reference as a seemingly return type
as PF1 (I observe that I should have better have used a
different name like RF instead).
> If my memory serves,
> Boost Bind sometimes uses <Fn(ArgTypes...)> with a function object
> type as Fn, but that is a means of pretty-printing error messages more
> than anything else. It could just as well use <Fn, ArgTypes...>.
This is correct and you can reasonably argue that if we had
variadic template parameters during the time, when result_of
was originally proposed (around 2003 out of my head), this
design would have been one reasonable candidate. I first
thought that result_of's design in C++0x won't make much sense,
but I changed my mind ;-) The advantage of the old and still
persistent
design is, that you can concentrate on a *single* type and you can
often prevent unnecessary packing and unpacking of template
parameters (not always, of-course).
> Perhaps the declaration was stated as such to create names for use in
> the other columns of the table. However, there is no way to know how
> all specializations (and some may be user-supplied) acquire the
> argument types from the function object type. And that may not even be
> necessary: for example, a partial specialization for
> std::unary_function could simply say "typedef result_type type;" For
> that matter, "typedef Fn type;" would seem to suffice in place of the
> given text. The current text is clearly an overspecification.
I don't think so, it is intended. In regard to result_type deduction:
This is not the job of result_of (even though it was suggested in
the first proposals and existed until TR1): The process of deducting
a possible return from typedefs is part of different processes,
especially related to /weak result types/ as in
std::reference_wrapper,
or std::function. See also
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1290
What we really lost is that currently result_of is no longer
completely
INVOKE-capable. A paper exists, that attempts to close this gap:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3123.html
I think that result_of's actual intention was to be able to represent
all combinations that are possible with INVOKE and the working
draft seems to use it in this manner, see e.g. [refwrap.invoke]
or std::bind ([func.bind.bind]).
> Recommended change: Don't specify a partial specialization. (In my
> opinion, the standard should never specify partial specializations
> anyway!)
>
> template <class Fn> struct result_of;
>
> Fn shall be a function object type (20.8), reference to function, or
> reference to function object type.
What would be the real advantage of this approach?
> The member typedef type shall name the type of a function call
> expression (5.2.2, 13.3.1.1) with Fn as the type of the postfix-
> expression. If the type of such an expression is not determined by Fn,
> the type of type is unspecified.
But that would be different from what result_of was intended for.
The advantage of the current state is, that user-code working with
INVOKE does not need to care about the nature of Fn.
HTH & Greetings from Bremen,
Daniel Kr=FCgler
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]