std::forward without perfect forwarding? - c++

Advice on std::forward is generally limited to the canonical use case of perfectly forwarding function template arguments; some commentators go so far as to say this is the only valid use of std::forward. But consider code like this:
// Temporarily holds a value of type T, which may be a reference or ordinary
// copyable/movable value.
template <typename T>
class ValueHolder {
public:
ValueHolder(T value)
: value_(std::forward<T>(value)) {
}
T Release() {
T result = std::forward<T>(value_);
return result;
}
private:
~ValueHolder() {}
T value_;
};
In this case, the issue of perfect forwarding does not arise: since this is a class template rather than a function template, client code must explicitly specify T, and can choose whether and how to ref-qualify it. By the same token, the argument to std::forward is not a "universal reference".
Nonetheless, std::forward appears to be a good fit here: we can't just leave it out because it wouldn't work when T is a move-only type, and we can't use std::move because it wouldn't work when T is an lvalue reference type. We could, of course, partially specialize ValueHolder to use direct initialization for references and std::move for values, but this seems like excessive complexity when std::forward does the job. This also seems like a reasonable conceptual match for the meaning of std::forward: we're trying to generically forward something that might or might not be a reference, only we're forwarding it to the caller of a function, rather than to a function we call ourselves.
Is this a sound use of std::forward? Is there any reason to avoid it? If so, what's the preferred alternative?

std::forward is a conditional move-cast (or more technically rvalue cast), nothing more, nothing less. While using it outside of a perfect forwarding context is confusing, it can do the right thing if the same condition on the move applies.
I would be tempted to use a different name, even if only a thin wrapper on forward, but I cannot think of a good one for the above case.
Alternatively make the conditional move more explicit. Ie,
template<bool do_move, typename T>
struct helper {
auto operator()(T&& t) const
-> decltype(std::move(t))
{
return (std::move(t));
}
};
template<typename T>
struct helper<false, T> {
T& operator()(T&& t) const { return t; }
};
template<bool do_move, typename T>
auto conditional_move(T&& t)
->decltype( helper<do_move,T>()(std::forward<T>(t)) )
{
return ( helper<do_move,T>()(std::forward<T>(t)) );
}
that is a noop pass-through if bool is false, and move if true. Then you can make your equivalent-to-std::forward more explicit and less reliant on the user understanding the arcane secrets of C++11 to understand your code.
Use:
std::unique_ptr<int> foo;
std::unique_ptr<int> bar = conditional_move<true>(foo); // compiles
std::unique_ptr<int> baz = conditional_move<false>(foo); // does not compile
On the third hand, the kind of thing you are doing above sort of requires reasonably deep understanding of rvalue and lvalue semantics, so maybe forward is harmless.

This sort of wrapper works as long as it's used properly. std::bind does something similar. But this class also reflects that it is a one-shot functionality when the getter performs a move.
ValueHolder is a misnomer because it explicitly supports references as well, which are the opposite of values. The approach taken by std::bind is to ignore lvalue-ness and apply value semantics. To get a reference, the user applies std::ref. Thus references are modeled by a uniform value-semantic interface. I've used a custom one-shot rref class with bind as well.
There are a couple inconsistencies in the given implementation. The return result; will fail in an rvalue reference specialization because the name result is an lvalue. You need another forward there. Also a const-qualified version of Release, which deletes itself and returns a copy of the stored value, would support the occasional corner case of a const-qualified yet dynamically-allocated object. (Yes, you can delete a const *.)
Also, beware that a bare reference member renders a class non-assignable. std::reference_wrapper works around this as well.
As for use of forward per se, it follows its advertised purpose as long as it's passing some argument reference along according to the type deduced for the original source object. This takes additional footwork presumably in classes not shown. The user shouldn't be writing an explicit template argument… but in the end, it's subjective what is good, merely acceptable, or hackish, as long as there are no bugs.

Related

C++ When to use const Reference over Forwarding Reference

Consider we need to implement a function f with a templated argument T t. The function should not copy t and accept both rvalues and lvalues, therefore two implementations are possible:
template <class T>
void f(const T& t) { ... }
template <class T>
void f(T&& t) { ... }
If we want to change t inside of f or need to preserve the value category, we have to use the second version. So by this line of thought when and why would we go for the first option?
You'll mainly go for the first option when you want to give strong guarantee to the clients of your function that t won't be changed inside of f. Although you can drop the const qualifier and still not modify t, it's considered good practice and good interface design to qualify as const a parameter if you don't change it's referred to value inside a function, plus it helps the compiler to optimize the code better.
As an extra, know that you can use const_cast to hack around the type safety of const if you really must, but recall that you're doing exactly that: getting rid of the type safety. Avoid this at all cost.
And lastly, a const qualifier doesn't prevent copying, you can easily do something like:
int main()
{
const int a = 3;
int b = a; // a is copied to b
}
In this generic scenario, there is no reason to write both overloads.
If f will only observe its argument, then only the const T& overload is needed.
If f will just forward its argument to some other function, then only the T&& overload is needed, and will use std::forward<T>. (This includes the case where the function needs to retain a copy of the value, i.e., forward it to a copy/move constructor.)

Should I pass by const reference or by value in a template function?

When choosing to pass by const reference vs. by value, the choice seems clear for large classes: gotta use const ref to avoid an expensive copy since copy elision is permitted only in limited circumstances (if copy constructor has no side effects or if the copy was from an rvalue).
For smaller classes, it seems passing by value is more attractive:
it's just as fast as dereferencing
it avoids aliasing (which is both bug-prone and bad for performance as it forces the compiler to be more conservative)
if a copy is necessary anyway, it makes the copy in the scope where the compiler may be able to use copy elision
So what is the best practice when writing a template function, where it's not always obvious whether the class of the argument is large or small?
(Assuming that you only want to read from the value you're passing.)
I think that the best choice is passing by const&, as:
Some objects cannot be copied, are expensive to copy, or contain side-effects in their copy constructor.
While taking primitives by const& might result in a minor performance degradation, this is a smaller loss compared to the problems described in the bullet point above.
Ideally, you would want to do something like this (I'm not being careful about small classes that have side-effects in the copy constructor here):
template <typename T>
using readonly = std::conditional_t<
sizeof(T) <= sizeof(void*),
T,
const T&
>;
template <typename T>
void foo(readonly<T> x);
The problem is that T cannot be deduced from a call to foo, as it is in a "non-deducible context".
This means that your users will have to call foo<int>(0) instead of foo(0), as T=int cannot be deduced from the compiler.
(I want to reiterate that the condition I'm using above is very naive and potentially dangerous. You might want to simply check if T is a primitive or a POD smaller than void* instead.)
Another possible thing you can do is use std::enable_if_t to control what function gets called:
template <typename T>
auto foo(T x) -> std::enable_if_t<(sizeof(T) <= sizeof(void*))>;
template <typename T>
auto foo(const T& x) -> std::enable_if_t<(sizeof(T) > sizeof(void*))>;
live example on wandbox
This obviously requires a lot of extra boilerplate... maybe there will be a better solution using code generation when (if?) we'll get constexpr blocks and "metaclasses".
What you want is a type trait that tests if the type is a scalar and then switches on that
template <typename Type>
using ConstRefFast = std::conditional_t<
std::is_scalar<std::decay_t<Type>>::value,
std::add_const_t<Type>,
std::add_lvalue_reference_t<std::add_const_t<std::decay_t<Type>>>
>;
And then pass an object by reference like this
template <typename Type>
void foo(typename ConstRefFast<Type>::type val);
Note that this means that the function will not be able to deduce the type T automatically anymore. But in some situations it might give you what you want.
Note that when it comes to template functions, sometimes the question of ownership is more important than just whether you want to pass the value by const ref or by value.
For example consider a method that accepts a shared_ptr to some type T and does some processing on that pointer (either at some point in the future or immediately), you have two options
void insert_ptr(std::shared_ptr<T> ptr);
void insert_ptr(const std::shared_ptr<T>& ptr);
When the user looks at both of these functions, one conveys meaning and semantics clearly while the other just leaves questions in their mind. The first one obviously makes a copy of the pointer before the method starts, thus incrementing the ref count. But the second one's semantics is not quite clear. In an asynchronous setting this might leave room for doubt in the user's mind. Is my pointer going to be safely used (and object safely released) if for example the pointed to object is used at some point in the future asynchronously?
You can also consider another case that does not consider asynchronous settings. A container that copies values of type T into internal storage
template <typename T>
class Container {
public:
void set_value(T val) {
this->insert_into_storage(std::move(val));
}
};
or
template <typename T>
class Container {
public:
void set_value(const T& val) {
this->insert_into_storage(val);
}
};
Here the first one does convey the fact the value is copied into the method, after which the container presumably stores the value internally. But if the question of lifetime of the copied object is not important, then the second one is more efficient, simply because it avoids an extra move.
So in the end it just comes down to whether you need clarity of your API or performance.
I think as a basic rule, you should just pass by const&, preparing your generic template code for the general case of expensive-to-copy objects.
For example, if you take a look at std::vector's constructors, in the overload that takes a count and a value, the value is simply passed by const&:
explicit vector( size_type count,
const T& value = T(),
const Allocator& alloc = Allocator())

What is the correct argument type for a function-object?

I have a templated function that receives function-objects. Sometimes the function-objects are stateless structs, but sometimes they are large statefull objects. The state of the function-object is not changed in this function, only examined. I'm also very keen on writing code that the compiler can optimize as much as possible. What should I consider when choosing the argument type?
The function is of this type:
template<typename funcT>
auto make_particle(funcT fun) {
Particle<typename funcT::result_type> particle;
particle = fun();
return particle;
}
The argument type should probably be funcT const & fun so that the large objects are not copied, but why do most people use call-by-value function objects? Do I loose something by using const reference? Or should I use lvalue-reference? Please note that c++1y is ok and that the code example above is just an example.
There are several use cases, which should all be available:
The functor has no state and is supplied as a temporary: make_particle(MyFun())
The functor has a state which needs to be recovered later: YourFun f; make_particle(f);
You cannot solve both cases with one single reference type parameter: The first case requires a const lvalue reference or an rvalue reference, which forbids the second use, and the second case requlres an lvalue reference, which forbids the first use.
A common idiom in such situations is to accept the functor by value, and return it at the end:
template <typename Iter, typename F>
F map(Iter first, Iter last, F f)
{
// ... f(*first) ...
return f;
}
That may not be entirely applicable in your case, though, but it's an idea. For example, you could return a std::pair<ParticleType, F>. In any case you'd require your functor type to be copyable, but that's a reasonable requirement.
An alternative, helpfully pointed out by #Xeo, and available for function templates only, is to take the functor argument by universal reference, which will work in both cases:
template <typename Iter, typename F>
void map(Iter first, Iter last, F && f)
{
// ... use f(*first) ...
}
Note that in this case we do not use std::forward, since we are using f as a genuine reference, and not just to pass it through somewhere else. In particular, we are not allowed to move-from f if we still plan to use it.
The argument type should probably be funcT const & fun so that the
large objects are not copied,
That is not the view taken by the algorithms in the standard libraries. There, callable objects are taken by value. It's up to the author of the callable object to ensure that it's reasonably cheap to copy. For example if it needs access to something large, then you can have the user of the functor provide a reference to one and store that in the functor -- copying a reference is cheap.
Now, it may be that you want to do things differently from the standard library because you expect particle-making functions to be unusually difficult to make cheap to copy or move. But C++ programmers are familiar with functors being copied, so if you do what the standard library does then usually you aren't making their lives any worse than they were already. Copying functors isn't an issue unless you make it one :-)

When should I use forward and move?

I have a code that operates on a vector:
template<typename T>
void doVector(vector<T>& v, T&& value) {
//....
v.push_back(value);
//...
}
For normal push_back, do I need to use forward(value), move(value) or just value (according to new C++11) ? and how do they impact the performance?
For example,
v.push_back(forward<T>(value));
The current code will not compile when the second argument is lvalue because T&& will turn out to be X& which means T needs to be X& which in turn means std::vector<T> will become std::vector<X&> which will NOT match the first argument which is std::vector<X> &. Hence, it is an error.
I would use two template parameters:
template<typename T, typename V>
void doVector(vector<T> & v, V && value)
{
v.emplace_back(std::forward<V>(value));
}
Since V could a different type from T, so emplace_back makes more sense, because not only it solves the problem, it makes the code more generic. :-)
Now the next improvement : since we're using emplace_back which creates the object of type T from argument value (possibly using constructor), we could take advantage of this fact, and make it variadic function:
template<typename T, typename ...V>
void doVector(vector<T> & v, V && ... value)
{
v.emplace_back(std::forward<V>(value)...);
}
That is even more generic, as you could use it as:
struct point
{
point(int, int) {}
};
std::vector<point> pts;
doVector(pts, 1, 2);
std::vector<int> ints;
doVector(ints, 10);
Hope that helps.
forward(value) is used if you need perfect forwarding meaning, preserving things like l-value, r-value.
forwarding is very useful because it can help you avoid writing multiple overloads for functions where there are different combinations of l-val, r-val and reference arguments
move(value) is actually a type of casting operator that casts an l-value to an r-value
In terms of performances both avoid making extra copies of objects which is the main benefit.
So they really do two different things
When you say normal push_back, I'm not sure what you mean, here are the two signatures.
void push_back( const T& value );
void push_back( T&& value );
the first one you can just pass any normal l-val, but for the second you would have to "move" an l-val or forward an r-val. Keep in mind once you move the l-val you cannot use it
For a bonus here is a resource that seems to explain the concept of r-val-refs and other concepts associated with them very well.
As others have suggested you could also switch to using emplace back since it actually perfect forwards the arguments to the constructor of the objects meaning you can pass it whatever you want.
When passing a parameter that's a forwarding reference, always use std::forward.
When passing a parameter that's an r-value, use std::move.
E.g.
template <typename T>
void funcA(T&& t) {
funcC(std::forward<T>(t)); // T is deduced and therefore T&& means forward-ref.
}
void funcB(Foo&& f) {
funcC(std::move(f)); // f is r-value, use move.
}
Here's an excellent video by Scott Meyers explaining forwarding references (which he calls universal references) and when to use perfect forwarding and/or std::move:
C++ and Beyond 2012: Scott Meyers - Universal References in C++11
Also see this related question for more info about using std::forward: Advantages of using forward
http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11
That video, IMO, has the best explanation of when to use std::forward and when to use std::move. It presents the idea of a Universal Reference which is IMO an extremely useful tool for reasoning about move semantics.

rvalue references and constructor arguments

Lets consider a simple class
template< typename T >
class Wrapper {
public:
// Constructors?
private:
T wrapped;
};
What constructors should it use to be effective?
Before C++0x there would be a constructor that takes either:
const reference (T const&) - if type T is "heavy",
or value (T) - if type T is "light".
Determining whether type T is "heavy" or "light" is not easy.
One could assume only build-in types (ints/floats/...) are "light". But that is not fully correct since our own Wrapper<int> most likely should be considered a "light" type as well.
Libraries like boost::call_traits provide some means to overcome this difficulty by allowing type creator to mark the type as "light" (by providing proper call_traits specialization). Otherwise it will be treated as "heavy". Seems acceptable.
But C++0x makes it worse. Because now you have also rvalue reference (T&&) which allows to efficiently take (some) "heavy" objects.
And because of this now you have to chose among:
just const reference (T const&) - if type T is "heavy" and does not support move semantics (because either there is none - like with large PODs - or none was written and you have no influence on that),
both const reference (T const&) and rvalue reference (T&&) - if type T is "heavy" and does support move semantics,
just value (T) - if type T is "light" or if it is "heavy" but supports move semantics (even if copy is made it doesn't bother use since otherwise we would have to copy from T const& ourselves anyway...).
Still its not easy to tell which types are "heavy" and which are "light" (as previously). But now you are also unable to tell whether type T supports move semantics or not (or are you?).
This becomes even more annoying once you wrap more than one value since number of possible constructor overloads grows exponentially.
Is there any solution to that problem?
I though about some template constructors for forwarding (perfect forwarding) arguments but I wasn't sure whether that would work as desired. And also it would allow to provide values of different type that would be just forwarded to T constructor. This might be considered a feature but does not have to.
On the contrary, C++11 makes it easier thanks to universal references:
template <typename T> struct Wrapper
{
T value;
template <typename U> Wrapper(U && u)
: value(std::forward<U>(u))
{ }
};
As an extra nice touch, you should add a defaulted second argument that only exists when T is constructible from U, so as to not make your class itself appear constructible from unmatching types. And make it variadic, too:
template <typename ...Args>
Wrapper(Args &&... args,
typename std::enable_if<std::is_constructible<T, Args...>::value, int>::type = 0)
: value(std::forward<Args>(args)...)
{ }
Make sure to #include <utility> for forward and #include <type_traits> for the traits.
If you are going to copy your T anyway, it might be better to pass the parameter by value and let the compiler figure out the copying. Whatever you do, there is going to be at least one copy anyway.
template< typename T >
class Wrapper {
public:
  Wrapper(T value) : wrapped(std::move(value))
{ }
private:
  T wrapped;
};
See Want speed? Pass by value by Dave Abrahams.