I am trying to figure out if my use of std::forward in the following code makes sense even though it is not a forwarding (=universal) reference. Please excuse the amount of code, but this is the stripped-down version of what I am trying to achieve.
template <class... Args>
class event_dispatcher {
private:
using func_t = std::function<bool(Args...)>;
public:
bool operator()(Args... args) const {
for (auto& f : funcs) {
if (!f(args...))
return false;
}
return true;
}
template <class F>
std::enable_if_t<std::is_invocable_r_v<bool, F, Args...>>
add(F&& f) {
funcs.emplace_back(std::forward<F>(f));
}
template <class F>
std::enable_if_t<!std::is_invocable_r_v<bool, F, Args...> && std::is_invocable_v<F, Args...>>
add(F&& f) {
add([f_ = std::forward<F>(f)](Args... args){
std::invoke(f_, std::forward<Args>(args)...); // <-- this is the one I am asking about!
return true;
});
}
private:
std::vector<func_t> funcs;
};
The idea is that if the callable passed to add() doesn't return a bool, we will wrap it in a lambda that does.
Now, if I just pass args... directly, it will always work, but if any of Args are rvalues then it will needlessly do a copy instead of a move. If I instead use std::move(args)... it will not work if any of Args is an lvalue. Using std::forward<Args>(args)... here seems to solve these problems and work as efficiently as possible in any case, but I am worried that I am missing something since I am using std::forward for a non-forwarding reference, and in general I am having a lot of trouble wrapping my head around the whole reference collapsing / rvalue reference / std::move / std::forward issues.
std::move does not move std::forward does not forward.
std::forward is a conditional move. std::forward<T> moves if T is a value or rvalue reference.
This lines up with when you want to move args..., so it is appropriate here.
A comment along those lines should be a good idea, as in any situation where you use std::forward outside of simple forwarding references.
Related
I have the following api:
old_operation(stream, format, varArgs);
And I want to write an adaptor to make it possible to write the call as follows:
stream << operation(format, varArgs);
To do this I'm using a temporary object which stores references to varArgs and overload the operator<< to apply the old_operation() as follows:
template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
template<typename ...T>
class Operation
{
using Storage = decltype(storage(std::declval<T>()...));
public:
template<typename ...Args>
explicit Operation(Args&& ...args) :
mArgs(storage(std::forward<Args>(args)...)) {};
template<class StreamType>
StreamType& Apply(StreamType& stream)
{
auto f = [&](auto&& ...xs)
{
old_operation(stream, std::forward<decltype(xs)>(xs)...);
}
mArgs(f);
return stream;
}
private:
Storage mArgs;
};
template<typename ...Args>
Operation<Args...> MakeOperation(Args&&... args)
{
return Operation<Args...>(std::forward<Args>(args)...);
}
template<class StreamType, typename ...Args>
StreamType& operator<<(StreamType& stream, Operation<Args...>&& operation)
{
return operation.Apply(stream);
}
This works great but now I need to add some using namespace declarations embedded into the operation call:
let's say I have
namespace X {namespace Y { namespace Z { int formater(double x) { return std::round(x); }}}
And I don't want to add all the namespaces for this call, so I'm doing something like:
#define OPERATION(...) \
[&]() { \
using namespace ::X:Y:Z; \
return Operation("" __VA_ARGS__); }() \
which allows me to do:
stream << OPERATION(format, formater(2.3));
The problem with the lambda is that the temporaries are being created in a different scope than the Apply() call, which is UB.
I don't know if by adding a const qualifier to mArgs it will prolong the life of the captured references as mentioned here. I'm not sure if this applies, I'm assuming they are stack-based references and that by adding the const qualifier to mArgs the qualifier is going to be applied to the captured references.
template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
this is a haskell-style functor (well, a variardic one, which isn't very haskell). It takes Ts... and returns a function of type ((Ts...)->U)->U, ie that knows how to evaluate a function on the arguments you passed to it. This makes storage of type (Ts...)->( ((Ts...)->U)->U ) for a bit of algebraic fun.
I suspect your problem is that you have temporaries that you don't store. Generally not storing temporaries passed to a function, where the return value depends on the lifetime of those temporaries, results in fragile code.
If you have C++1z experimental::apply we can do this:
template<class... Ts>
decltype(auto) storage(Ts&&... ts) {
return
[tup=std::tuple<Ts...>(std::forward<Ts>(ts)...)]
(auto&& f)
->decltype(auto) mutable
{
return std::experimental::apply(decltype(f)(f), std::move(tup));
};
}
which returns a one-shot delayed call to std::apply. Apply takes a function and a tuple, and passes the arguments of the tuple to the function. It handles reference and r/lvalue-ness properly. Meanwhile, the container of the tuple makes the capture simpler, and lets us easily conditionally store rvalues while keeping lvalues as references.
I think this solves your problem, as temporaries get moved-into the tuple instead of being captured by reference, while non-temporaries are stored by reference.
There should be std::experimental::apply implementations that are better than anything I can sketch here available easily.
In this question I talked about how to create a multi-function memoizator. In one of the answers, it was suggested to implement perfect forwarding, so passing the arguments to desired function will result inexpensive, like this:
template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) //rvalue reference of args
{
auto it = multiCache.find(memFunc.name);
if (it == multiCache.end())
throw KeyNotFound(memFunc.name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(forward<Args> (args) ...);//perfect forwarding
}
I'm not an expert of move semantic and perfect forwarding, but from what I've understood we need to pass an rvalue when we call callFunction.
So the first callFunction calling is illegal, while the second one is:
typedef vector<double> vecD;
MultiMemoizator mem;
//lambda function that returns the sorted vector (just for fun)
function<vecD(vecD)> sort_vec = [](vecD vec) {
sort(vec.begin(),vec.end());
return vec;
};
vector<vecD> vec;
// here fill vec...
mem.callFunction<double, double>(sortFunc, vec); //error! vec is an lvalue
mem.callFunction<double, double>(sortFunc, move(vec));//OK: move(vec) return an rvalue of the lvalue (vec)
The problem is that in this application, callFunction is supposed to be called several times on the same object, which is not supposed to happen once we call move on our object.
So for example:
mem.callFunction<double, double>(sortFunc, move(vec));//First time: sorting will take A LONG time because vec is not memoized
//now is not safe to use vec anymore...but it's memoized for sortFunc
mem.callFunction<double, double>(sortFunc, move(vec));//computed quickly because of memoization, but unsafe because of first move!
So from what I can understand I have to make a choice:
Give up on perfect forwarding implementing callFunction(MemFunc<ReturnType, Args...> memFunc, Args ... args) (or Args & ... args) , but introducing an expensive copy when we call cachedFunc(args)
Keep the efficient perfect forwarding, but introduce possible unexpected behaviour on multiple move on the same object
Obviously the second choice is not acceptable, so how can I avoid the first one?
A POSSIBLE SOLUTION:
The solution posted above is too much restrictive for the user: what if he wants, for some reason, to use vec again? So a possible solution could be to overload callFunction so it accept both solutions:
//rvalue reference/move/perfect forwarding implementation
template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) {
...
return cachedFunc(forward<Args> (args) ...);//perfect forwarding
}
//lvalue reference/no perfect forwarding implementation
template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args& ... args) {
...
return cachedFunc(args);//expensive!
}
This solution has some disadvantage or could lead to some problem?
This seems like something that ought to be frequently asked and answered, but my search-fu has failed me.
I'm writing a function which I want to accept a generic callable object of some kind (including bare function, hand-rolled functor object, bind, or std::function) and then invoke it within the depths of an algorithm (ie. a lambda).
The function is currently declared like this:
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
I'm accepting the functor by reference because I want to guarantee that it does not get copied on entry to the function, and thus the same instance of the object is actually called. And it's a const reference because this is the only way to accept temporary objects (which are common when using hand-rolled functors or bind).
But this requires that the functor implement operator() as const. I don't want to require that; I want it to be able to accept both.
I know I can declare two copies of this method, one that accepts it as const and one as non-const, in order to cover both cases. But I don't want to do that as the comments are hiding quite a lot of code that I don't want to duplicate (including some loop constructs, so I can't extract them to a secondary method without just moving the problem).
I also know I could probably cheat and const_cast the functor to non-const before I invoke it, but this feels potentially dangerous (and in particular would invoke the wrong method if the functor intentionally implements both const and non-const call operators).
I've considered accepting the functor as a std::function/boost::function, but this feels like a heavy solution to what ought to be a simple problem. (Especially in the case where the functor is supposed to do nothing.)
Is there a "right" way to satisfy these requirements short of duplicating the algorithm?
[Note: I would prefer a solution that does not require C++11, although I am interested in C++11 answers too, as I'm using similar constructs in projects for both languages.]
Have you tried a forwarding layer, to force inference of the qualifier? Let the compiler do the algorithm duplication, through the normal template instantiation mechanism.
template<typename T, typename F>
size_t do_something_impl(const T& a, F& f)
{
T internal_value(a);
const T& c_iv = interval_value;
// do some complicated things
// loop {
// loop {
f(c_iv, other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something(const T& a, F& f)
{
return do_something_impl<T,F>(a, f);
}
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
return do_something_impl<T,const F>(a, f);
}
Demo: http://ideone.com/owj6oB
The wrapper should be completely inlined and have no runtime cost at all, except for the fact that you might end up with more template instantiations (and therefore larger code size), though that will only happen when for types with no operator()() const where both const (or temporary) and non-const functors get passed.
Answer for new relaxed requirements.
In commentary on another answer the OP has clarified/changed the requirements to…
“I'm ok with requiring that if the functor is passed in as a temporary
then it must have an operator() const. I just don't want to limit it
to that, such that if a functor is not passed in as a temporary (and
also not a const non-temporary, of course) then it is allowed to have
a non-const operator(), and this will be called”
This is then not a problem at all: just provide an overload that accepts a temporary.
There are several ways of distinguishing the original basic implementation, e.g. in C++11 an extra default template argument, and in C++03 an extra defaulted ordinary function argument.
But the most clear is IMHO to just give it a different name and then provide an overloaded wrapper:
template<typename T, typename F>
size_t do_something_impl( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something( T const& a, F const& f)
{ return do_something_impl( a, f ); }
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{ return do_something_impl( a, f ); }
Note: there's no need to specify the do_something_impl instantiation explicitly, since it's inferred from the lvalue arguments.
The main feature of this approach is that it supports simpler calls, at the cost of not supporting a temporary as argument when it has non-const operator().
Original answer:
Your main goal is to avoid copying of the functor, and to accept a temporary as actual argument.
In C++11 you can just use an rvalue reference, &&
For C++03 the problem is a temporary functor instance as actual argument, where that functor has non-const operator().
One solution is to pass the burden to the client code programmer, e.g.
require the actual argument to be an lvalue, not a temporary, or
require explicit specification that the argument is a temporary, then take it as reference to const and use const_cast.
Example:
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
enum With_temp { with_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_temp, F const& f )
{
return do_something( a, const_cast<F&>( f ) );
}
If it is desired to directly support temporaries of const type, to ease the client code programmer's life also for this rare case, then one solution is to just add an additional overload:
enum With_const_temp { with_const_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_const_temp, F const& f )
{
return do_something( a, f );
}
Thanks to Steve Jessop and Ben Voigt for discussion about this case.
An alternative and much more general C++03 way is to provide the following two little functions:
template< class Type >
Type const& ref( Type const& v ) { return v; }
template< class Type >
Type& non_const_ref( Type const& v ) { return const_cast<T&>( v ); }
Then do_something, as given above in this answer, can be called like …
do_something( a, ref( MyFunctor() ) );
do_something( a, non_const_ref( MyFunctor() ) );
Why I didn't think of that immediately, in spite of having employed this solution for other things like string building: it's easy to create complexity, harder to simplify! :)
Is there a good way to forward arguments of a function f to a function g in a situation like
template<typename... T>
void g(T && ... x);
template<typename... T>
void f(T && ... x)
{
g(x..., x...);
}
In the next code x could be moved twice
template<typename... T>
void f(T && ... x)
{
g(std::forward<T>(x)..., std::forward<T>(x)...);
}
In the next code std::forward<T>(x)... could be evaluated before x...
template<typename... T>
void f(T && ... x)
{
g(x..., std::forward<T>(x)...);
}
std::forward doesn't move things - it creates a reference that says "it is ok to move from me". The actual moving occurs inside g, not in f where std::forward or std::move is called.
The problem of move is only one of the problems here. There is also the problem of passing the same object twice as a reference in two spots, which is generally considered quite rude!
We can fix that by creating temporary objects in f and pass those by reference, but that leads to a serious issue: references are often used to return values from a function, and we have the same variable being used twice -- we cannot return both results.
So the answer is "don't do that", because it is not in general safe. You have to know the semantics of both g and f to figure out what the correct thing to do is, and a simple forwarding type interface won't reflect the depth of knowledge required.
If you do have deep semantic understanding of what g and f are supposed to do, then the situation changes.
You can in general force the order using
using separate statements (obviously)
expressions separated by the comma operator. (Beware of overloaded operator,)
The use of brace initialization works because the order of evaluation of the arguments in a brace initializer list is the order in which they appear1. The following has well-defined evaluation order:
std::tuple<T..., T...> args {
std::forward<T>(x)...,
std::forward<T>(x)... }; // still not sane, but evaluation order defined
But it's still useless as g(...) might still move from the same reference twice. What you'd actually want for rvalue refs is not:
g(rvalue, std::move(rvalue)); // or
g(std::move(rvalue), rvalue); // or even
g(std::move(rvalue), std::move(rvalue)); // [sic]
The only sane way would be:
g(lvalue=std::move(rvalue), lvalue); // BUT: fix the evaluation order
So how do we achieve precisely that but generically?
Enter Indices?!
Let's say you have variadic g as you described:
template<typename... T>
void g(T && ... x)
{
}
Now, you can duplicate the arguments passed to f using
the index trick:
namespace detail // indices
{
template<std::size_t... Is> struct seq{};
template<std::size_t I, std::size_t... Is>
struct gen_seq : gen_seq<I-1, I-1, Is...>{};
template<std::size_t... Is>
struct gen_seq<0, Is...>{ using type = seq<Is...>; };
}
and an invoker helper function:
#include <tuple>
template<typename Tuple, std::size_t... Is>
void f_invoke_helper(Tuple const& tup, detail::seq<Is...>)
{
g(std::get<Is>(tup)..., std::get<Is>(tup)...);
}
All that's required next is to tie it all together:
template<typename... T>
void f(T && ... x)
{
f_invoke_helper(
std::make_tuple(std::forward<T>(x)...),
typename detail::gen_seq<sizeof...(T)>::type());
}
Note that if you pass rvalue-refs, it will get moved once (into the tuple) and used twice (as a lvalue) in the invoker helper:
int main()
{
std::string x = "Hello world";
int i = 42;
// no problem:
f(i, -42, std::move(x));
}
Hope this helps!
PS. As it has been aptly pointed out, it's probably a lot easier to just say
template<typename... T>
void f(T&&... x) { g(x..., x...); }
I haven't thought of a way in which the tuple idiom doesn't result in the same, except for actually moving movable arguments into the tuple.
1The semantics of T{...} are described in 12.6.1See also: how to avoid undefined execution order for the constructors when using std::make_tuple .
I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]