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.
Related
Is there any reason that c++ compiler gives error when using two different numeric variable types in std::max() function? (e.g. int and long).
I mean something like: "Sometimes we have this problem when using std::max() function for two different numeric variable types, so the compiler gives error to prevent this problem".
The compiler produces an error because it cannot perform type deduction for the template argument of std::max. This is how std::max template is declared: the same type (template parameter) is used for both arguments. If the arguments have different types, the deduction becomes ambiguous.
If you work around the deduction ambiguity by supplying the template argument explicitly, you will be able to use different types as std::max arguments
std::max(1, 2.0); // Error
std::max<double>(1, 2.0); // OK
The reason why std::max insists on using a common type for its arguments (instead of using two independent types) is described in #bolov's answer: the function actually wants to return a reference to the maximum value.
std::max returns a reference to the argument that has the maximum value. The main reason it is this way is because it is a generic function and as such it can be used with types expensive to copy. Also you might actually need just a reference to the object, instead a copy of it.
And because it returns a reference to a argument, all arguments must be of the same type.
The direct answer to the question is that it's because std::min and std::max take only one template parameter that defines the types of both arguments. If/when you try to pass arguments of different types, the compiler can't decide which of those two types to use for the template argument, so the code is ambiguous. As originally defined in C++98, std::min and std::max had signatures like these (C++03, §[lib.alg.min.max]):
template<class T> const T& min(const T& a, const T& b);
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp);
template<class T> const T& max(const T& a, const T& b);
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp);
So the basic idea here is that the function receives two objects by reference, and returns a reference to one of those objects. If it received objects of two different types, it wouldn't be able to return a reference to an input object because one of the objects would necessarily be of a different type than it was returning (so #bolov is correct about that part, but I don't think it's really the whole story).
With a modern compiler/standard library, if you don't might dealing with values instead of references, you could pretty easily write code on this general order:
template <class T, class U>
std::common_type<T, U> min(T const &a, U const &b) {
return b < a ? b : a;
}
template <class T, class U>
std::common_type<T, U> max(T const &a, U const &b) {
return a < b ? b : a;
}
That makes it pretty easy to deal with your case of passing an int and a long (or other pairs of types, as long as std::common_type can deduce some common type for them, and a<b is defined for objects of the two types.
But, in 1998, even if std::common_type had been available so it was easy to do, that solution probably wouldn't have been accepted (and as we'll see, it's still open to some question whether it's a great idea)--at the time, many people still thought in terms of lots of inheritance, so it was (more or less) taken for granted that you'd frequently use it in situations where both arguments were really of some derived type, something on this general order:
class Base {
// ...
virtual bool operator<(Base const &other);
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Base {
// ...
};
Derived1 d1;
Derived2 d2;
Base &b = std::max(d1, d2);
In this case, the version above that returns a value instead of returning a reference would cause a serious problem. common_type<Derived1, Derived2> is going to be Base, so we'd end up slicing the argument to create an object of type Base, and returning that. This would rarely provide desirable behavior (and in some cases, such as if Base were an abstract base class, it wouldn't even compile).
There's one other point that's probably worth noting: even when applied in a seemingly simple situation, std::common_type can produce results you might not expect. For example, let's consider calling the template defined above like:
auto x = min(-1, 1u);
That leaves us with an obvious question: what type will x be?
Even though we've passed it an int and an unsigned, the type of the result is (at least potentially) neither int or unsigned (e.g., quite possibly long long)!
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.)
Is there any reason that c++ compiler gives error when using two different numeric variable types in std::max() function? (e.g. int and long).
I mean something like: "Sometimes we have this problem when using std::max() function for two different numeric variable types, so the compiler gives error to prevent this problem".
The compiler produces an error because it cannot perform type deduction for the template argument of std::max. This is how std::max template is declared: the same type (template parameter) is used for both arguments. If the arguments have different types, the deduction becomes ambiguous.
If you work around the deduction ambiguity by supplying the template argument explicitly, you will be able to use different types as std::max arguments
std::max(1, 2.0); // Error
std::max<double>(1, 2.0); // OK
The reason why std::max insists on using a common type for its arguments (instead of using two independent types) is described in #bolov's answer: the function actually wants to return a reference to the maximum value.
std::max returns a reference to the argument that has the maximum value. The main reason it is this way is because it is a generic function and as such it can be used with types expensive to copy. Also you might actually need just a reference to the object, instead a copy of it.
And because it returns a reference to a argument, all arguments must be of the same type.
The direct answer to the question is that it's because std::min and std::max take only one template parameter that defines the types of both arguments. If/when you try to pass arguments of different types, the compiler can't decide which of those two types to use for the template argument, so the code is ambiguous. As originally defined in C++98, std::min and std::max had signatures like these (C++03, §[lib.alg.min.max]):
template<class T> const T& min(const T& a, const T& b);
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp);
template<class T> const T& max(const T& a, const T& b);
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp);
So the basic idea here is that the function receives two objects by reference, and returns a reference to one of those objects. If it received objects of two different types, it wouldn't be able to return a reference to an input object because one of the objects would necessarily be of a different type than it was returning (so #bolov is correct about that part, but I don't think it's really the whole story).
With a modern compiler/standard library, if you don't might dealing with values instead of references, you could pretty easily write code on this general order:
template <class T, class U>
std::common_type<T, U> min(T const &a, U const &b) {
return b < a ? b : a;
}
template <class T, class U>
std::common_type<T, U> max(T const &a, U const &b) {
return a < b ? b : a;
}
That makes it pretty easy to deal with your case of passing an int and a long (or other pairs of types, as long as std::common_type can deduce some common type for them, and a<b is defined for objects of the two types.
But, in 1998, even if std::common_type had been available so it was easy to do, that solution probably wouldn't have been accepted (and as we'll see, it's still open to some question whether it's a great idea)--at the time, many people still thought in terms of lots of inheritance, so it was (more or less) taken for granted that you'd frequently use it in situations where both arguments were really of some derived type, something on this general order:
class Base {
// ...
virtual bool operator<(Base const &other);
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Base {
// ...
};
Derived1 d1;
Derived2 d2;
Base &b = std::max(d1, d2);
In this case, the version above that returns a value instead of returning a reference would cause a serious problem. common_type<Derived1, Derived2> is going to be Base, so we'd end up slicing the argument to create an object of type Base, and returning that. This would rarely provide desirable behavior (and in some cases, such as if Base were an abstract base class, it wouldn't even compile).
There's one other point that's probably worth noting: even when applied in a seemingly simple situation, std::common_type can produce results you might not expect. For example, let's consider calling the template defined above like:
auto x = min(-1, 1u);
That leaves us with an obvious question: what type will x be?
Even though we've passed it an int and an unsigned, the type of the result is (at least potentially) neither int or unsigned (e.g., quite possibly long long)!
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.