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.
Related
I'm trying to define a C++ concept for standard library containers that allow push_back/emplace_back:
template <class ContainerType>
concept PushBackContainer = requires(ContainerType a)
{
requires SequenceContainer<ContainerType>;
{ a.push_back(typename ContainerType::const_reference& v) };
{ a.push_back(typename ContainerType::value_type&& v) };
// How do you define a variable templated function:
{ template< class... Args > a.emplace_back(Args&&... args) };
}
The problem I have is how do I define emplace_back with its variadic template arguments? I'm using Visual Studio 2019 but if this isn't supported I'd be interested in the correct syntax come the time it is.
Probably about the best that's worth doing is just a.emplace_back();.
Your push_back requirements don't have a correct syntax, either. I think you want:
template <class ContainerType>
concept PushBackContainer = requires(
ContainerType& a,
typename ContainerType::value_type const& cv,
typename ContainerType::value_type& v)
{
requires SequenceContainer<ContainerType>;
a.push_back(cv);
a.push_back(std::move(v));
a.emplace_back();
};
Requirements don't check for a function signature; they check for the validity of an expression (without instantiating more templates than necessary). If we had a class like:
class StrangeContainer {
public:
using value_type = std::string;
using const_reference = const value_type&;
private:
struct ValueHolder {
ValueHolder(const std::string& s) : value(s) {}
ValueHolder(std::string&& s) : value(std::move(s)) {}
std::string value;
};
public:
void push_back(ValueHolder);
template <typename ... Args>
void emplace_back(Args&&...);
};
then ignoring SequenceContainer requirements, PushBackContainer<StrangeContainer> would be true, and it would also satisfy the Standard's own requirements related to push_back. It satisfies the technical requirements, even though it has some surprising effects like the fact that push_back("") is ill-formed.
So for push_back, we're really just checking that it can be called with a const lvalue and with a non-const rvalue. (The Standard actually also requires that it can be called with a non-const lvalue and with a const rvalue, and these cases have the same behavior as when called with a const lvalue.)
(If you really wanted to test for an exact push_back signature, you could try static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back); - but this is not recommended, since member functions in namespace std are not required to have signatures exactly as described, only to be callable with the same arguments as if declared as described.)
Also, the standard container class templates don't have any constraints on their push_back or emplace_back functions. Every instantiation of the templates which have push_back declares both overloads, whether or not the type is copyable and/or movable. If not, it would be an error to actually call or otherwise odr-use the push_back function, but it "exists" for purposes of requires-expressions and SFINAE contexts. Likewise, the emplace_back member template is declared to accept any number of arguments with any types and value categories, no matter whether they can be used as value_type constructor arguments or not.
So what we would want to test to find out if the container has an emplace_back with an essentially ordinary variadic function declaration would need to be phrased as: Can emplace_back be called with any number of arguments, with each having any possible type and each being either an lvalue or rvalue? I don't think there's any way to really answer that within C++, using requires-expressions, SFINAE tricks, or otherwise. So I would just do one simple test for existence of some sort of emplace_back, and that test might as well be as simple as possible: zero arguments.
You could get fancier and also test for some additional cases: Does emplace_back accept different numbers of arguments, up to some fixed maximum? Does it accept lvalue and rvalue arguments? Does it accept arguments of dummy struct types? Dummy struct types that aren't MoveConstructible? const, volatile, and const volatile types? All possible combinations of all of the above? But since you'll never cover all the cases, how much value does each partial enhancement like this really give, compared to the effort, complexity, and maintenance needed to add checks?
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())
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.
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.
I currently have a class hierarchy like
MatrixBase -> DenseMatrix
-> (other types of matrices)
-> MatrixView -> TransposeView
-> DiagonalView
-> (other specialized views of matrices)
MatrixBase is an abstract class which forces implementers to define operator()(int,int) and such things; it represents 2 dimensional arrays of numbers. MatrixView represents a (possibly mutable) way of looking at a matrix, like transposing it or taking a submatrix. The point of MatrixView is to be able to say something like
Scale(Diagonal(A), 2.0)
where Diagonal returns a DiagonalView object which is a kind of lightweight adapter.
Now here's the question(s). I will use a very simple matrix operation as an example. I want to define a function like
template <class T>
void Scale(MatrixBase<T> &A, const T &scale_factor);
which does the obvious thing the name suggests. I want to be able to pass in either an honest-to-goodness non-view matrix, or an instance of a subclass of MatrixView. The prototype as written above does not work for statements such as
Scale(Diagonal(A), 2.0);
because the DiagonalView object returned by Diagonal is a temporary, and Scale takes a non-const reference, which cannot accept a temporary. Is there any way to make this work? I tried to use SFINAE, but I don't understand it all that well, and I'm not sure if that would solve the problem. It is important to me that these templated functions can be called without providing an explicit template argument list (I want implicit instantiation). Ideally the statement above could work as written.
Edit: (followup question)
As sbi responded below about rvalue references and temporaries, Is there a way to define two versions of Scale, one which takes a non-const rvalue reference for non-views, and one which takes a pass-by-value view? The problem is to differentiate between these two at compile time in a way such that implicit instantiation will work.
Update
I've changed the class hierarchy to
ReadableMatrix
WritableMatrix : public ReadableMatrix
WritableMatrixView
DenseMatrix : public WritableMatrix
DiagonalView : public WritableMatrixView
The reason WritableMatrixView is distinct from WritableMatrix is that the view must be passed around by const reference, while the matrices themselves must be passed around by non-const ref, so the accessor member functions have different const-ness. Now functions like Scale can be defined as
template <class T>
void Scale(const WritableMatrixView<T> &A, const T &scale_factor);
template <class T>
void Scale(WritableMatrix<T> &A, const T &scale_factor){
Scale(WritableMatrixViewAdapter<T>(A), scale_factor);
}
Note that there are two versions, one for a const view, and a non-const version for actual matrices. This means for functions like Mult(A, B, C), I will need 8 overloads, but at least it works. What doesn't work, however is using these functions within other functions. You see, each View-like class contains a member View of what it's looking at; for example in the expression Diagonal(SubMatrix(A)), the Diagonal function returns an object of type DiagonalView<SubMatrixView<T> >, which needs to know the fully derived type of A. Now, suppose within Scale I call some other function like it, which takes either a base view or matrix reference. That would fail because the construction of the needed View's require the derived type of the argument of Scale; information it does not have. Still working on find a solution to this.
Update
I have used what is effectively a home-grown version of Boost's enable_if to select between two different versions of a function like Scale. It boils down to labeling all my matrix and view classes with extra typedef tags indicating if they are readable and writable and view or non-view. In the end, I still need 2^N overloads, but now N is only the number of non-const arguments. For the final result, see the here (it's unlikely to get seriously revamped again).
This has nothing to do with templates. Your example
Scale(Diagonal(A), 2.0);
could be generalized to
f(g(v),c);
In C++03, this requires the first parameter to f() to either be passed per copy or per const reference. The reason is that g() returns a temporary, an rvalue. However, rvalues only bind to const references, but not to non-const references. This is independent of whether templates, SFINAE, TMP or whatnot are involved. It's just the way the language (currently) is.
There's also a rationale behind that: If g() returns a temporary, and f() modifies that temporary, then nobody has a chance to "see" the modified temporary. Thus the modification is done in vain and the whole thing is most likely an error.
As far as I understood you, in your case the result of g() is a temporary that's a view onto some other object (v), so modifying it would modify v. But if that's the case, in current C++, the result of g() must either be const (so that it can be bound to a const reference or it must be copied. Since const "smells" wrong to me, making that view cheap to copy would probably be the best thing.
However, there's more to this. C++1x will introduce what's called rvalue references. What we know as "references" will then be divided into either lvalue reference or rvalue references. You will be able to have functions take rvalue references and even overload based on "l/rvalue-ness". This was thought out to allow class designers to overload copy ctor and assignment for rvalue right-hand sides and having them "steal" the right-hand side's values, so that copying rvalues will e cheaper. But you could probably use it to have Scale take an rvalue and modify that.
Unfortunately your compiler very likely doesn't support rvalue references yet.
Edit (followup question):
You cannot overload f(T) with f(T&) to achieve what you want. While only the former will be used for rvalues, lvalues can bind to either argument equally well, so invoking that f with an lvalue is ambiguous and results in a compile-time error.
However, what's wrong with having an overload for DiagonalView:
template <class T>
void Scale(MatrixBase<T> &matrix, const T &scale_factor);
template <class T>
void Scale(DiagonalView<T> view, const T &scale_factor);
Is there anything I'm missing?
Another edit:
I would need a ridiculously large number of overloads then, since there are currently more than 5 views, and there are several dozen functions like Scale.
Then you would need to group together those types that can be handled in the same way. You could use some simple template-meta stuff to do the grouping. Off the top of my head:
template<bool B>
struct boolean { enum { result = B }; };
template< typename T >
class some_matrix {
public:
typedef boolean<false> is_view;
// ...
};
template< typename T >
class some_view {
public:
typedef boolean<true> is_view;
// ...
};
namespace detail {
template< template<typename> class Matrix, typename T >
void Scale(Matrix<T>& matrix, const T& scale_factor, boolean<true>)
{
/* scaling a matrix*/
}
template< template<typename> class Matrix, typename T >
void Scale(View<T>& matrix, const T& scale_factor, boolean<true>)
{
/* scaling a view */
}
}
template< template<typename> class Matrix, typename T >
inline void Scale(Matrix<T>& matrix, const T& scale_factor)
{
detail::Scale( matrix, scale_factor, typename Matrix<T>::is_view() );
}
This particular setup/grouping might not exactly fit your needs, but you can setup something like this in ways that fit for yourself.
An easy way to fix this would be to use boost::shared_ptr< MatrixBase<T> > instead of a reference.
May be, you should use const. ?
template <class T>
void Scale(const MatrixBase<T> &A, const T &scale_factor);
you are limiting the type of the first argument of Scale, but you can let the compiler figure out what type would be appropriate on its own, like this:
template <class M,class T>
void Scale(M A, const T &scale_factor);
Don't use references, pass by value.
Let copy elision do the optimization for you, if needed.