Reputation: 13
I have writing code like:
template<bool B, typename IfT, typename ThenT>
using conditional_t = std::conditional_t<B, IfT, ThenT>;
template <bool B,
typename IfT, typename ThenT>
constexpr auto conditional_v(IfT&& t1, ThenT&& t2)
-> conditional_t<B, IfT, ThenT> {
if constexpr (B) {
return t1;
} else {
return t2;
}
}
If passed by value like conditional_v<true>(0, 1)
, we can get
template<>
inline constexpr conditional_t<true, int, int> conditional_v<true, int, int>(int && t1, int && t2)
{
if constexpr(true) {
return t1;
}
}
if passed by reference like conditional_v<true>(i, j)
, we will get
template<>
inline constexpr conditional_t<true, int &, int &> conditional_v<true, int &, int &>(int & t1, int & t2)
{
if constexpr(true) {
return t1;
}
}
When I refer to the stl, for example the max
template< class T >
constexpr const T& max( const T& a, const T& b );
They are mostly passed by const T&
instead of T&&
.
So I got the question: Should I use const T&
in my situation(just like conditional_t, conditional_v designed to choose one initial value at comipler time(int, literal string, etc...)).
Upvotes: 1
Views: 127
Reputation: 117433
Should I use
const T&
instead ofT&&
in my code like stl?
If I understand your question correctly, you should use T&&
to enable forwarding:
#include <utility>
template<bool B, class T, class F>
constexpr decltype(auto) conditional_v(T&& t, F&& f)
{
if constexpr(B) return std::forward<T>(t);
else return std::forward<F>(f);
}
Upvotes: 0
Reputation: 592
T&& was introduced to avoid unnecessary copies by "stealing" the passed object resources. Suppose object rhs has a pointer to some allocated resource rhs.p then a typical use would be
void steal (T&& rhs){
p=rhs.p;
rhs.p=nullptr;
}
Since in your case std::max
does not intend to change the parameters there is no reason to pass the arguments by rvalue reference. Also you will not be able to use it with lvalue references.
The const T&
allow us to pass temporaries in addition to named variables. For example
struct Test {};
Test returnObject(){
Test t;
return t;
}
int main(){
Test x;
Test& y=x;
Test&& z=x;//error cannot bind rvalue to lvalue
Test& r=returnObject();// error: cannot bind lvalue to rvalue
const Test& a=returnObject();// OK
Test&& b=returbObject();// OK
}
Upvotes: 1
Reputation: 16670
Consider the following code:
int foo = bar(); // some function that returns a value we don't know
int foo2 = std::max(foo, 100); // make sure it's no more than 100
How would you write that code if std::max
took it's arguments by &&
?
Upvotes: 0