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.
Related
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.)
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())
I looked recently at this video explaining the ideas of concepts lite in C++, which are likely to appear this year as a TS. Now, I also learned about universal references/forwarding references (as described here) and that T&& can have two meanings depending on the context (i.e. if type deduction is being performed or not). This leads naturally to the question how concepts will interact with universal references?
To make it concrete, in the following example we have
void f(int&& i) {}
int i = 0;
f(i); // error, looks for f(int&)
f(0); // fine, calls f(int&&)
and
template <typename T>
void f(T&& test) {}
int i = 0;
f(i); // fine, calls f(T&&) with T = int& (int& && = int&)
f(0); // fine, calls f(T&&) with T = int&& (int&& && = int&&)
But what happens if we use concepts?
template <typename T>
requires Number<T>
void f(T&& test) {}
template <Number T>
void g(T&& test) {}
void h(Number&& test) {}
int i = 0;
f(i); // probably should be fine?
f(0); // should be fine anyway
g(i); // probably also fine?
g(0); // fine anyway
h(i); // fine or not?
h(0); // fine anyway
Especially the last example bothers me a bit, since there are two conflicting
principles. First, a concept used in this way is supposed to work just as a type and second, if T is a deduced type, T&& denotes a universal reference instead of an rvalue reference.
Thanks in advance for clarification on this!
It all depends on how the concept itself is written. Concepts-Lite itself (latest TS as of this writing) is agnostic on the matter: it defines mechanisms by which concepts may be defined and used in the language, but does not add stock concepts to the library.
On the other hand document N4263 Toward a concept-enabled standard library is a declaration of intent by some members of the Standard Committee that suggests the natural step after Concepts-Lite is a separate TS to add concepts to the Standard Library with which to constrain e.g. algorithms.
That TS may be a bit far down along the road, but we can still take a look at how concepts have been written so far. Most examples I’ve seen somewhat follow a long tradition where everything revolves around a putative, candidate type that is usually not expected to be a reference type. For instance some of the older Concepts-Lite drafts (e.g. N3580) mention concepts such as Container which have their roots in the SGI STL and survive even today in the Standard Library in the form of 23.2 Container requirements.
A telltale pre-forwarding reference sign is that associated types are described like so:
Value type X::value_type The type of the object stored in a container. The value type must be Assignable, but need not be DefaultConstructible.
If we translate this naïvely to Concepts-Lite, it could look like:
template<typename X>
concept bool Container = requires(X x) {
typename X::value_type;
// other requirements...
};
In which case if we write
template<typename C>
requires Container<C>
void example(C&& c);
then we have the following behavior:
std::vector<int> v;
// fine
// this checks Container<std::vector<int>>, and finds
// std::vector<int>::value_type
example(std::move(v));
// not fine
// this checks Container<std::vector<int>&>, and
// references don't have member types
example(v);
There are several ways to express the value_type requirement which handles this situation gracefully. E.g. we could tweak the requirement to be typename std::remove_reference_t<X>::value_type instead.
I believe the Committee members are aware of the situation. E.g. Andrew Sutton leaves an insightful comment in a concept library of his that showcases the exact situation. His preferred solution is to leave the concept definition to work on non-reference types, and to remove the reference in the constraint. For our example:
template<typename C>
// Sutton prefers std::common_type_t<C>,
// effectively the same as std::decay_t<C>
requires<Container<std::remove_reference_t<C>>>
void example(C&& c);
T&& always has the same "meaning" -- it is an rvalue reference to T.
The interesting thing happens when T itself is a reference. If T=X&&, then T&& = X&&. If T=X& then T&& = X&. The rule that an rvalue reference to an lvalue reference is an lvalue reference is what allows the forwarding reference technique to exist. This is called reference collapsing1.
So as for
template <typename T>
requires Number<T>
void f(T&& test) {}
this depends on what Number<T> means. If Number<T> permits lvalue references to pass, then that T&& will work like a forwarding reference. If not, T&& it will only bind to rvalues.
As the rest of the examples are (last I checked) defined in terms of the first example, there you have it.
There may be additional "magic" in the concepts specification, but I am not aware of it.
1 There is never actually a reference-to-a-reference. In fact, if you type int y = 3; int& && x = y; that is an illegal expression: but using U = int&; U&& x = y; is perfectly legal, as reference collapsing occurs.
An analogy to how const works sometimes helps. If T const x; is const regardless of if T is const. If T_const is const, then T_const x; is also const. And T_const const x; is const as well. The constness of x is the max of the constness of the type T and any "local" modifiers.
Similarly, the lvalue-ness of a reference is the max of the lvalue-ness of the T and any "local" modifiers. Imagine if the language had two keywords, ref and lvalue. Replace & with lvalue ref and && with ref. The use of lvalue without ref is illegal under this translation..
T&& means T ref. If T was int lvalue ref, then reference collapsing results in int lvalue ref ref -> int lvalue ref, which translates back as int&. Similarly, T& translates to int lvalue ref lvalue ref -> int lvalue ref, and if T=int&&, then T& translates to int ref lvalue ref -> int lvalue ref -> int&.
This is a difficult thing. Mostly, when we write concepts, we want to focus on the type definition (what can we do with T) and not its various forms (const T, T&, T const&, etc). What you generally ask is, "can I declare a variable like this? Can I add these things?". Those questions tend to be valid irrespective of references or cv-qualifications. Except when they aren't.
With forwarding, template argument deduction frequently gives you those over forms (references and cv-qualified types), so you end up asking questions about the wrong types. sigh. What to do?
You either try to define concepts to accommodate those forms, or you try to get to the core type.
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 :-)
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.