From: Andy Venikov on
Hi,

Given: need to implement a perfect-forwarding function f.

First attempt:

template <typename Func, typename ... Prms>
inline
typename std::result_of<Func(Prms...)>::type
f(Func && f, Prms && ... prms)
{
return f(std::forward<Prms>(prms)...);
}

The implementation seems reasonable - it'll be able to accept any callable entity, not just a function (i.e. it'll work with functors, function pointers, function references).

I was wandering, if it was better to not directly return a call to f(...), but a moved version of it?

I.e:
return std::move(f(std::forward<Prms>(prms)...);

When the returned objects are movable, this version seems more adequate.

But is it safe?

Thanks,
Andy.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Andy Venikov on
Andy Venikov wrote:
> Hi,
>
> Given: need to implement a perfect-forwarding function f.
>
> First attempt:
>
> template <typename Func, typename ... Prms>
> inline
> typename std::result_of<Func(Prms...)>::type
> f(Func && f, Prms && ... prms)
> {
> return f(std::forward<Prms>(prms)...);
> }
>
> The implementation seems reasonable - it'll be able to accept any
> callable entity, not just a function (i.e. it'll work with functors,
> function pointers, function references).
>
> I was wandering, if it was better to not directly return a call to
> f(...), but a moved version of it?
>
> I.e:
> return std::move(f(std::forward<Prms>(prms)...);
>
> When the returned objects are movable, this version seems more adequate.
>
> But is it safe?
>
> Thanks,
> Andy.
>
Well, after thinking about it more it looks like move serves no purpose.

Since a return from a function is never an lvalue (either an rvalue or a reference), std::move in this context is just useless.

Thanks anyway,
Andy.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Howard Hinnant on
On May 7, 2:15 pm, Andy Venikov <swojchelo...(a)gmail.com> wrote:
> Hi,
>
> Given: need to implement a perfect-forwarding function f.
>
> First attempt:
>
> template <typename Func, typename ... Prms>
> inline
> typename std::result_of<Func(Prms...)>::type
> f(Func && f, Prms && ... prms)
> {
> return f(std::forward<Prms>(prms)...);
>
> }
>
> The implementation seems reasonable - it'll be able to accept any callable entity, not just a function (i.e. it'll work with functors, function pointers, function references).
>
> I was wandering, if it was better to not directly return a call to f(...), but a moved version of it?
>
> I.e:
> return std::move(f(std::forward<Prms>(prms)...);
>
> When the returned objects are movable, this version seems more adequate.
>
> But is it safe?

If f() returns an rvalue, there is no need for std::move. All
std::move() does is cast an expression to an rvalue. If f() returns
an lvalue (such as an A&), you probably don't want to cast it to an
rvalue as you might then end up implicitly moving from something you
didn't intend (such as a data member if f() is a member function or
has friend access to the data member).

-Howard


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Mathias Gaunard on
On 7 mai, 19:15, Andy Venikov <swojchelo...(a)gmail.com> wrote:

> I was wandering, if it was better to not directly return a call to f(...), but a moved version of it?
>
> I.e:
> return std::move(f(std::forward<Prms>(prms)...);
>
> When the returned objects are movable, this version seems more adequate.
>
> But is it safe?

It is yes, but it is perfectly useless. Your expression is already a
temporary. std::move is used to "transform" a named variable into a
temporary.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: SG on
On 7 Mai, 20:15, Andy Venikov wrote:
> Hi,
>
> Given: need to implement a perfect-forwarding function f.
>
> First attempt:
>
> template <typename Func, typename ... Prms>
> inline
> typename std::result_of<Func(Prms...)>::type
> f(Func && fun, Prms && ... prms)
> {
> return fun(std::forward<Prms>(prms)...);
> }
>
> The implementation seems reasonable - it'll be able to accept any
> callable entity, not just a function (i.e. it'll work with functors,
> function pointers, function references).
>
> I was wondering, if it was better to not directly return a call to
> fun(...), but a moved version of it?
>
> I.e:
> return std::move(fun(std::forward<Prms>(prms)...);
>
> When the returned objects are movable, this version seems more adequate.

Actually, it isn't "more adequate". If result_of<>::type is an object
type, the function call is already an rvalue. The same is true if
result_of<>::type is an rvalue reference type. In case
result_of<>::type is an lvalue reference type, your modification won't
compile because
- move "converts" the lvalue to an rvalue
- you try to initialize an lvalue reference (the return value of f)
with an rvalue expression (the result of move).

std::move does not need to be used on a function call expression --
unless the function returns an lvalue reference and you want to
deliberately turn it into an rvalue. There are even situations where
the use of std::move might prevent a compiler from doing a copy
elision. Keep in mind that C++0x already forces a compiler to
automatically move-construct objects in cases where copy elision is
allowed but technically not possible and a move constructor is
available. So, std::move should only be used if necessary.

Cheers,
SG


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]