Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++0x: result_of and decltype

122 views
Skip to first unread message

Scott Meyers

unread,
May 7, 2009, 2:16:37 PM5/7/09
to
In C++0x, what is the difference between decltype(f(args)) and
result_of<f(args)>::type? If there is no difference, why do we need
both, e.g.,
why don't we just leave result_of in std::tr1?

I assume that in decltype(expr), expr is not evaluated, but I can't find
wording
to that effect in N2800. Can somebody point me to the guarantee or
disabuse me
of my incorrect assumption?

Thanks,

Scott

--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

SG

unread,
May 8, 2009, 4:18:58 PM5/8/09
to
On 7 Mai, 20:16, Scott Meyers <use...@aristeia.com> wrote:
> In C++0x, what is the difference between decltype(f(args)) and
> result_of<f(args)>::type? If there is no difference, why do we need
> both, e.g.,
> why don't we just leave result_of in std::tr1?

The difference is that result_of requires a function signature (f and
args are types) and decltype requires a valid expression (f = function/
function pointer/reference/functor, args = objects).

Another question you could ask is: Why do we need result_of where we
have the Callable concept std::Callable<f,args>::result_type. The
answer to that would be: concepts only work in templates (as fas as I
know) and Callable requires you to specify the types 'f' and 'args'
separately whereas result_of only requires one type (function
signature).

> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?

I think it's a safe bet to say decltype doesn't evaluate the
expression (except for the type). It can be used in contexts where
expressions can't be evaluated (outside of a function's body, for
example).

auto foo(int a, int b) -> decltype(a+b)
{ return a+b; }

Cheers!
SG

Pete Becker

unread,
May 8, 2009, 4:18:01 PM5/8/09
to
Scott Meyers wrote:

In C++0x, what is the difference between decltype(f(args)) and
result_of<f(args)>::type? If there is no difference, why do we
need both, e.g.,
why don't we just leave result_of in std::tr1?


decltype applies to expressions, and result_of applies to (abused) types.

struct S
{
int operator()(int);
};
S s;
decltype(s(3)) // int
result_of<S(int)>::type // int

typedef int (*pf)(int);
int f(int);
decltype(f(3) // int
result_of<pf(int)>::type // int


I assume that in decltype(expr), expr is not evaluated, but I
can't find wording
to that effect in N2800. Can somebody point me to the guarantee
or disabuse me
of my incorrect assumption?


It's in an unnumbered paragraph (probably should be numbered)
immediately after [dcl.type.simple]/4:

The operand of the decltype specifier is
an unevaluated operand (Clause 5).


--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

daniel....@googlemail.com

unread,
May 8, 2009, 4:18:33 PM5/8/09
to
On 7 Mai, 20:16, Scott Meyers <use...@aristeia.com> wrote:
> In C++0x, what is the difference between decltype(f(args)) and
> result_of<f(args)>::type? If there is no difference, why do we need
> both, e.g.,
> why don't we just leave result_of in std::tr1?

Result_of and decltype are quite different beasts. While decltype
evaluates a given expression, result_of evaluates a *constructed*
expression from the given template argument type. The difference
becomes clearer with an example. Consider

struct A {
double operator()(bool, int);
};

To determine the result type of the operator()
overload you would evaluate

std::result_of<A(bool, int)>::type

but above declaration doesn't allow you directly to
use decltype. You would be required to apply your
own construction by writing something like

decltype(((*((A*)0))(false, 0));

to determine the result of the operator() overload.

In this sense result_of is much nearer to
concept Callable than to decltype, where you
would write

std::Callable<A, bool, int>::result_type

instead.

I can easier think of result_type as some kind of
type trait and it's specification should be moved
to 20.6.2 [meta.type.synop] instead.

> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?

N2857, 7.1.6.2 [dcl.type.simple]/2:

"[..] The operand of the decltype specifier is an unevaluated operand
(Clause 5)."

Greetings from Bremen,

Daniel

vaughn

unread,
May 8, 2009, 9:01:17 PM5/8/09
to
result_of<f(5)>::type would not be valid, since f(5) is not a type.
decltype(f(5)) would be fine.

On May 7, 2:16 pm, Scott Meyers <use...@aristeia.com> wrote:
> In C++0x, what is the difference between decltype(f(args)) and
> result_of<f(args)>::type? If there is no difference, why do we need
> both, e.g.,
> why don't we just leave result_of in std::tr1?
>
> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?
>
> Thanks,
>
> Scott
>
> --
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]

> [ your news-reader. If that fails, use mailto:std-...@netlab.cs.rpi.edu]

James Hopkin

unread,
May 8, 2009, 9:01:37 PM5/8/09
to

Scott Meyers wrote:
> In C++0x, what is the difference between decltype(f(args)) and
> result_of<f(args)>::type? If there is no difference, why do we need
> both, e.g.,
> why don't we just leave result_of in std::tr1?
>

Whereas result_of takes a type, decltype takes an expression.

> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?

7.1.6.2/4 says:

The operand of the decltype specifier is an unevaluated operand

James

wasti...@gmx.net

unread,
May 8, 2009, 9:20:56 PM5/8/09
to
On May 7, 8:16 pm, Scott Meyers <use...@aristeia.com> wrote:
> In C++0x, what is the difference between decltype(f(args)) and
> result_of<f(args)>::type? If there is no difference, why do we need
> both, e.g.,
> why don't we just leave result_of in std::tr1?

The paragraph describing result_of is hard to understand, but I
believe that result_of<F(Args)>::type == remove_reference<decltype(f
(args))>::type.
Even if this is not so, the obvious advantage of result_of is that you
don't have to obtain instances of F or Args by some dirty trick. In my
equality above, how would I write f and args?

> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?

7.1.6.2/p4 says: "The operand of the decltype specifier is an
*unevaluated* operand." (emphasis mine)

Sebastian

SG

unread,
May 8, 2009, 9:27:15 PM5/8/09
to
On 8 Mai, 22:18, Pete Becker <p...@versatilecoding.com> wrote:
> struct S
> {
> int operator()(int);
> };
>
> S s;
> decltype(s(3)) // int
> result_of<S(int)>::type // int

Interesting. I thought it was a "std::function"-like function
signature which in this case -- S(int) -- returned an object of type
S. But after checking N2857 again a conforming definition of result_of
seems to be

template<typename T> class result_of; // undefined

template<typename Fn, typename ... Args>
requires std::Callable<Fn,Args...> // <-- missing in the draft?
class result_of<Fn(Args...)> {
public:
typedef std::Callable<Fn,Args...>::result_type type;
};


Cheers!
SG


--

Joe Smith

unread,
May 8, 2009, 9:21:45 PM5/8/09
to

Scott Meyers wrote:
> I assume that in decltype(expr), expr is not evaluated, but I can't find
> wording
> to that effect in N2800. Can somebody point me to the guarantee or
> disabuse me
> of my incorrect assumption?

You are correct in that decltype does not evaluate its argument.

In N2875, this is stated in [dcl.type.simple]/4 as "The operand of the
decltype specifier is an unevaluated operand (Clause 5)."

I'm guessing it was the same location in N2800, but I did not check.

Thomas J. Gritzan

unread,
May 13, 2009, 11:40:25 PM5/13/09
to
SG schrieb:

> Another question you could ask is: Why do we need result_of where we
> have the Callable concept std::Callable<f,args>::result_type. The
> answer to that would be: concepts only work in templates (as fas as I
> know) and Callable requires you to specify the types 'f' and 'args'
> separately whereas result_of only requires one type (function
> signature).

When I read 3.4.3.3 correctly, you can use concepts anywhere.

So

typename result_of<...>::type

would be equivalent to

Callable<...>::result_type

, useable anywhere you can specify a type,
and you don't need the keyword 'typename'.

--
Thomas

SG

unread,
May 15, 2009, 2:06:35 PM5/15/09
to
On 14 Mai, 05:40, "Thomas J. Gritzan" <phygon_antis...@gmx.de> wrote:
>
> When I read 3.4.3.3 correctly, you can use concepts anywhere.
>
> So
>
> typename result_of<...>::type
>
> would be equivalent to
>
> Callable<...>::result_type
>
> , useable anywhere you can specify a type,
> and you don't need the keyword 'typename'.

Nice. Right. It reminded me that something similar is done in the for-
range loop where

for (... : (range expression)) ...

is translated to

{
auto && __range = (range expression);
for(auto __beg = std::Range<__RangeT>::begin(__range),
__end = std::Range<__RangeT>::end(__range);
...
}

The type __RangeT is probably something like "typename
remove_reference<decltype(__range)>::type".


Cheers!
SG

Scott Meyers

unread,
May 21, 2009, 4:19:08 PM5/21/09
to
Pete Becker wrote:

decltype applies to expressions, and result_of applies to (abused) types.


It took a while for the now-obvious followup question to dawn on me:
why isn't decltype permitted to work with types? sizeof takes both
expressions and types, so why not decltype?

>From what I can tell, C++0x introduces three different ways to figure
out the return type of a function call: decltype, result_of, and
Callable. Callable is a concept, so it serves an independent role
from that of decltype and result_of, but is there a reason why
decltype can't subsume the role of result_of, allowing result_of to be
removed (while still remaining in TR1)?

Scott

--

Sean Hunt

unread,
May 22, 2009, 4:06:04 AM5/22/09
to
On May 21, 2:19 pm, Scott Meyers <use...@aristeia.com> wrote:
> decltype can't subsume the role of result_of, allowing result_of to be
> removed (while still remaining in TR1)?

As I understand it, the publication of C++1x with withdraw TR1 as a
normative standard, meaning all functionality must be in C++1x or not
at all. I could definitely be incorrect on this point, though. Someone
mind confirming/denying?

Sean Hunt

James Hopkin

unread,
May 22, 2009, 1:37:19 PM5/22/09
to
On May 21, 9:19 pm, Scott Meyers <use...@aristeia.com> wrote:
> Pete Becker wrote:
>
> decltype applies to expressions, and result_of applies to (abused) types.
>
> It took a while for the now-obvious followup question to dawn on me:
> why isn't decltype permitted to work with types? sizeof takes both
> expressions and types, so why not decltype?
>

Surely decltype on a type could only be an identity operation. Why
should it give the return type of a function type?

James

Pete Becker

unread,
May 23, 2009, 12:54:30 PM5/23/09
to
Sean Hunt wrote:
> On May 21, 2:19 pm, Scott Meyers <use...@aristeia.com> wrote:
>> decltype can't subsume the role of result_of, allowing result_of to be
>> removed (while still remaining in TR1)?
>
> As I understand it, the publication of C++1x with withdraw TR1 as a
> normative standard, meaning all functionality must be in C++1x or not
> at all. I could definitely be incorrect on this point, though. Someone
> mind confirming/denying?
>

I don't know what "C++1x" refers to, but there are no plans to withdraw TR1.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Scott Meyers

unread,
May 23, 2009, 1:07:37 PM5/23/09
to
Sean Hunt wrote:
> On May 21, 2:19 pm, Scott Meyers <use...@aristeia.com> wrote:
>> decltype can't subsume the role of result_of, allowing result_of to be
>> removed (while still remaining in TR1)?
>
> As I understand it, the publication of C++1x with withdraw TR1 as a
> normative standard, meaning all functionality must be in C++1x or not
> at all. I could definitely be incorrect on this point, though. Someone
> mind confirming/denying?

TR1 is a technical report, not a standard, and even the final version (
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf ) has
"Draft"
in the title. Furthermore, TR1 implementations that currently exist are
not
going to go away, so any code dependent on TR1 functionality that is not in
C++0x will be fine.

If decltype could be extended to apply to types as well as expressions,
it would
eliminate the need for result_of to be in the C++0x standard library
and would
eliminate a seemingly-gratuitous inconsistency between the applicability of
sizeof and decltype. However, I don't know if there are technical
reasons why
decltype needs to be restricted to expressions.

Scott

Scott Meyers

unread,
May 23, 2009, 1:37:15 PM5/23/09
to
James Hopkin wrote:
>
> Surely decltype on a type could only be an identity operation. Why
> should it give the return type of a function type?

This is a good point, but I guess I was thinking about an
expression-like form with types. That is, given,

int f(int);

decltype(f(22)) yields int. I agree that

decltype(int(int)); // not legal, but if it were

would return int(int). (Or maybe int (&)(int) -- I don't remember the
exact rules.) But f(int) is neither a type nor an expression, it's a
function call expression with a type supplied instead of an actual
argument. So it's not
unreasonable, I don't think, for

decltype(f(int)); // also not legal

to treat this the same as f(22) above. After all, the only thing that
matters in the expression is the type of the argument, not its value.

Scott

Pete Becker

unread,
May 23, 2009, 1:58:51 PM5/23/09
to
Scott Meyers wrote:
>
> Sean Hunt wrote:
>>
>> On May 21, 2:19 pm, Scott Meyers <use...@aristeia.com> wrote:
>>>
>>> decltype can't subsume the role of result_of, allowing result_of to be
>>> removed (while still remaining in TR1)?
>>
>> As I understand it, the publication of C++1x with withdraw TR1 as a
>> normative standard, meaning all functionality must be in C++1x or not
>> at all. I could definitely be incorrect on this point, though. Someone
>> mind confirming/denying?
>
> TR1 is a technical report, not a standard, and even the final version (
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf ) has "Draft"
> in the title.

Well, yes, DTR 19768 has "draft" in its title. "DTR" stands for "Draft
Technical Report". TR 19768:2007, published by ISO, does not, since
it's not a draft.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Scott Meyers

unread,
May 24, 2009, 4:52:39 PM5/24/09
to
Pete Becker wrote:
>
> Well, yes, DTR 19768 has "draft" in its title. "DTR" stands for "Draft
> Technical Report". TR 19768:2007, published by ISO, does not, since
> it's not a draft.

My understanding is that the DTR is essentially the same as the final
report (which I actually didn't even know existed). Is that correct?

Scott

--

Pete Becker

unread,
May 24, 2009, 6:38:09 PM5/24/09
to
Scott Meyers wrote:
> Pete Becker wrote:
>>
>> Well, yes, DTR 19768 has "draft" in its title. "DTR" stands for "Draft
>> Technical Report". TR 19768:2007, published by ISO, does not, since
>> it's not a draft.
>
> My understanding is that the DTR is essentially the same as the final
> report (which I actually didn't even know existed). Is that correct?
>

The technical content is the same. ISO may have modified the presentation.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

0 new messages