Simple question, why doesn't the following work (implying a copy of ci
)?
#include <utility>
int main(){
const int ci = 2;
std::forward<int>(ci);
}
prog.cpp: In function 'int main()':
prog.cpp:6:23: error: no matching function for call to 'forward(const int&)'
The problem manifested itself while writing some template stuff, where I have a simple holder type as follows. To avoid unnecessary copies, I use perfect forwarding where possible, but that turns out to be the root of the problem it seems.
template<class T>
struct holder{
T value;
holder(T&& val)
: value(std::forward<T>(val))
{}
};
template<class T>
holder<T> hold(T&& val){
// T will be deduced as int, because literal `5` is a prvalue
// which can be bound to `int&&`
return holder<T>(std::forward<T>(val));
}
template<class T>
void foo(holder<T> const& h)
{
std::tuple<T> t; // contrived, actual function takes more parameters
std::get<0>(t) = std::forward<T>(h.value); // h.value is `const T`
}
int main(){
foo(hold(5));
}
If any further information is needed, please let me know.
Any idea to circumvent this problem is greatly appreciated.
This:
#include <utility>
int main(){
const int ci = 2;
std::forward<int>(ci);
}
doesn't work because you can't implicitly cast away const
. std::forward<T>(u)
should be read as:
Forward
u
as aT
.
You are attempting to say:
Forward an lvalue `const int` as an rvalue `int`.
which throws away the const
. To avoid throwing away the const
you could:
#include <utility>
int main(){
const int ci = 2;
std::forward<const int>(ci);
}
which says:
Forward an lvalue `const int` as an rvalue `const int`.
In your code:
template<class T>
void foo(holder<T> const& h)
{
std::tuple<T> t; // contrived, actual function takes more parameters
std::get<0>(t) = std::forward<T>(h.value); // h.value is `const T`
}
the const
qualifier on h
impacts the data member selection expression h.value
. h.value
is a const
lvalue int
. You can use forward
to change that into a const
rvalue int
, or you could use forward
to pass it on unchanged (as a const
lvalue int
). You could even use forward
to add volatile
(though I can't think of a good reason to).
In your example, I'm seeing no reason to use forward
at all (unless you take the const
off of h
).
std::get<0>(t) = h.value; // h.value is `const T`
Your comment is even still correct.
It's a dry read, but N2951 surveys what you can and can not do with forward
and why. This was modified by N3143 just prior to standardization, but the use cases and rationale from are still valid and unchanged in the final N3143 formulation.
Things you can do with forward
:
Things you can not do with forward
:
int
as a double
).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With