Looking at Scott Meyer's Effective Modern C++ pages 200-201, the suggested simplified implementation of std::forward could be (did see the proper implementation elsewhere):
template <typename T>
T&& forward(std::remove_reference_t<T>& param)
{ return static_cast<T&&>(param); }
And when accepting an rvalue Widget, it becomes:
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
Now, if you take that substituted code, and do:
struct Widget { };
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
template <typename T>
void G(T&& uref)
{ }
template <typename T>
void F(T&& uref)
{ G(forward(uref)); }
int main()
{
Widget x;
F(std::move(x));
}
What I can't wrap my head around, and didn't see a direct answer on SO yet, is: in forward how does parameter Widget& param manage to accept Widget&& from F()? Normally gcc-5.0 would complain like so with non-template code:
error: invalid initialization of non-const reference of type ‘Widget&’ from an rvalue of type ‘std::remove_reference::type {aka Widget}’
(Question #27501400 nearly touches the topic, but not quite. It shows the standard as having both lvalue & and rvalue && versions.)
"Named rvalue references are lvalues",
so example works fine as noted in a comment.
Nevertheless your code could be modified to
template <typename T>
void F(T && uref)
{
G(forward(move(uref)));
}
which is accepted by another overload (compare):
template<typename T>
T && forward(typename std::remove_reference<T>::type & t)
{
return static_cast<T &&>(t);
}
template<typename T>
T && forward(typename std::remove_reference<T>::type && t)
{
static_assert(!std::is_lvalue_reference<T>::value, "T is an lvalue reference");
return static_cast<T &&>(t);
}
The second overload will be used for rvalue. It works if T is Widget or Widget && and the assert fails for Widget &.
Related
This question already has an answer here:
Why does std::forward have two overloads?
(1 answer)
Closed 5 years ago.
I have found in std library the following implementation of std::forward:
// TEMPLATE FUNCTION forward
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
constexpr _Ty&& forward(
typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
First function works obviously, but for second I cannot find usefull example.
If I try to do something like this:
template<class _Ty> inline
constexpr _Ty&& my_forward(
typename std::remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward an rvalue as an rvalue
static_assert(!std::is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
template<typename T>
T getRValue()
{
return std::remove_reference<T>::type{};
}
template<typename T>
void setValue(T && i)
{
my_forward<T>(getRValue<T>());
}
int main()
{
int i = 1;
setValue(i);
}
to check when second function is called, I have got the error:
Error C2664 '_Ty my_forward<T>(int &&) noexcept': cannot convert argument 1 from 'int' to 'int &&'
Does anybody know in which case second overloaded function (in my terms my_forward) is called ?
Or may be some good example for it ?
By the way my compiler is MSVC 2015
Thanks, all for help !!
int bad_forward_call() {
return std::forward<int&>(7);
}
this will invoke that version.
Note I'm forwarding an rvalue as an lvalue. Not allowed.
Your getRValue fails to get an rvalue if T is a reference type.
I have found cases in which this function is called:
my_forward<int&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it won't compile 'cause we try convert rvalue to lvalue
my_forward<int&&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it compiles successfully
If it may be useful for somebody, the purpose of std::forward is to forward operation to another class or function.
Consider the following example:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(t); // Every time called precompute(T & t)
}
or like this:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::move(t)); // Every time called precompute(T && t)
}
As you can see we have a problem !! Neither of two examples satisfied us.
In first example every time will be called lvalue function and nothing can be done to call first with rvalue.
In second example every time will be called rvalue function and nothing can be done to call first with lvalue.
The solution is to forward making decision to the called function:
template<typename T>
void precompute(T & t)
{
std::cout << "lvalue reference";
}
template<typename T,
std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
std::cout << "rvalue reference";
}
template<typename T>
void calculate(T && t)
{
precompute(std::forward<T>(t)); // Will be called either precompute(T & t) or precompute(T && t) depends on type of t
}
In this case we have to be sure that will be called appropriate version.
That is why we forward (means: "Please, check type of t and if it is rvalue -> call rvalue version of function, and if it is lvalue -> call lvalue version of function") this operation to called function.
Could anyone explain why compilers (g++, visual c++) fail to deduce the template argument in this case?
struct MyClass
{
void Foo(int x)& {}
void Foo(int x)&& {}
};
template<typename T>
void CallFoo(void(T::*func)(int)&)
{
//create instance and call func
}
int main()
{
CallFoo(&MyClass::Foo); // Fails to deduce T
}
Why compilers cannot deduce T to MyClass? This happens only for methods overloaded by ref qualifiers. If a method is overloaded by const-ness or parameter types, everything works fine.
It seems that only Clang can deduce T in this case.
Summarizing discussion in the comments:
the support for reference-qualified member functions as template arguments is a relatively new feature for some compilers. However, the latest versions of most compilers will compile such code.
For example:
#include <iostream>
struct MyClass
{
void Foo(int) const &
{
std::cout << "calling: void Foo(int) const &\n";
}
void Foo(int) const &&
{
std::cout << "calling: void Foo(int) const &&\n";
}
};
template<typename T>
void CallFoo_lvalue(void (T::*foo)(int) const &)
{
T temp;
(temp.*foo)(0);
}
template<typename T>
void CallFoo_rvalue(void (T::*foo)(int) const &&)
{
(T{}.*foo)(0);
}
int main()
{
CallFoo_lvalue(&MyClass::Foo);
CallFoo_rvalue(&MyClass::Foo);
}
Will compile with:
gcc (works from 7.0.0)
Visual C++ (works with v19.10.24903.0)
producing the following output:
calling: void Foo(int) const &
calling: void Foo(int) const &&
For those who are wondering what & and && are for: here's the quote from #JustinTime:
Basically, & is the lvalue ref-qualifier, and && is the rvalue
ref-qualifier (binds to temporary object); in his example, MyClass m;
m.Foo(3); would call the top one, while MyClass{}.Foo(3); would call
the bottom one. They act on the implicit object parameter; lvalue
ref-qualifier binds to lvalue reference, and rvalue ref-qualifier
binds to rvalue reference (functions that have neither take the
parameter as lvalue reference, but let it bind to either). Note that
they don't actually change *this's type.
If you want your template to bind to different reference types, you need to use the universal reference
template<typename T>
void func(T&& arg)
{
other_func(std::forward<T>(arg));
}
That will bind to either lvalue or rvalue references. std::forward will make sure the appropriate reference is used in subsequent calls. I'm not sure how to fit the double ampersand into your code, but maybe just
template<typename T>
void CallFoo(void(T::*func)(int)&&)
Perhaps better would be
template<typename func_t>
void CallFoo(func_t && f)
{
call(std::forward<func_t>(f));
}
template<typename func_t>
void call(typename std::remove_reference<func_t> & f)
{
f();
}
template<typename func_t>
void call(typename std::remove_reference<func_t> && f)
{
f();
}
or whatever syntax you need to invoke a function pointer, maybe *f();
And if you want to pass arguments as well:
template<typename func_t, typename ... args_t>
void CallFoo(func_t && f, args_t && ... args)
{
call(std::forward<func_t>(f), std::forward<args_t>(args)...);
}
template<typename func_t, typename ... args_t>
void call(typename std::remove_reference<func_t> & f, args_t && ... args)
{
f(std::forward<args_t>(args)...);
}
template<typename func_t, typename ... args_t>
void call(typename std::remove_reference<func_t> && f, args_t && ... args)
{
f(std::forward<args_t>(args)...);
}
Basically, I have the following situation
template <class GT>
GT create_graph(size_t n)
{
GT ret;
// some stuf on ret
return ret;
}
template <class GT>
void test(const GT & g)
{
// processing on g
}
template <class GT>
void test(GT && g)
{
test(g); // call to const GT& (lvalue version)
}
int main()
{
test(create_graph<Graph>(100));
test(create_graph<SGraph>(100));
test(create_graph<AGraph>(100));
}
All the three types (Graph, SGraph, AGraph) have copy and move constructors and assignment operators.
The rvalue version is temporal. Afterward I will write a specialized version. But in the meantime I call the lvalue version.
According to my understanding, the first line (and the following ones), creates an rvalue object (by calling to create_graph()). This rvalue is passed to the rvalue version of test() which call to lvalue version of test() (please correct me if this is not exactly true).
Now, for a reason that I can not understand, the rvalue version of test() falls in infinite recursion. Apparently, it deals gas a rvalue. As I see, the parameter g (without performing move o forward) is a lvalue.
I tested with two different compilers and in both my code falls in infinite recursion. So, I conclude that I have done something wrong, either by my lack of understanding or because something happens to the instance of GT that makes the compiler interpret g as an rvalue.
So, if anyone can propose an explanation to clarify me what is happening, then I will be very grateful
Your temporary objects are not const, so you call the universal-reference function overload recursively. Use this instead:
template <class GT>
void test(GT && g)
{
test(static_cast<std::remove_reference_t<GT> const&>(g));
}
Another option suggested by Scott Meyers is to use a dispatch:
template <class GT>
void test(GT &&g, std::true_type)
{
//implementation for l-value references
}
template <class GT>
void test(GT &&g, std::false_type)
{
//implementation for r-value references
}
and then call those from the original function
template <class GT>
void test(GT &&g)
{
test(std::forward<GT>(g), std::is_lvalue_reference<GT>());
}
template <class GT>
void test(GT&& g) // universal reference
{
test(g); // equivalent to test<GT&>(g)
}
calls itself as g is a non const lvalue.
As you only want to forward to the other overload and the rvalue can be bind to const reference, you may omit completely template <class GT> void test(GT&& g) and keep only template <class GT> void test(const GT& g).
The implementation of std::forward in VS2013 is
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg)
{ // forward an lvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward anything
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
One version for lvalue reference, one version for rvalue reference. Why not just use a universal reference for both rvalue and lvalue reference:
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
Your version is not standard-compliant, as std::forward is is required to not compile when called with on an rvalue if T is an l-value reference. From [forward]:
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
2 Returns: static_cast<T&&>(t).
3 if the second form is instantiated with an lvalue reference type, the program is ill-formed.
std::forward is defined in this way to ensure that (some) misuses of std::forward do not compile. See n2951 for more discussion (although even n2951 does not use this exact form).
I'm expanding a bit on the problem you've pointed out here.
Your version would introduce a reference-dangling case if you attempt to bind a newly created rvalue to a l-value reference.
As Mankarse linked, the n2951 paper cites this case and, by simplifying it a bit, you can summarize it with the following code
#include <iostream>
using namespace std;
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
class Container
{
int data_;
public:
explicit Container(int data = 1) // Set the data variable
: data_(data) {}
~Container() {data_ = -1;} // When destructed, first set the data to -1
void test()
{
if (data_ <= 0)
std::cout << "OPS! A is destructed!\n";
else
std::cout << "A = " << data_ << '\n';
}
};
// This class has a reference to the data object
class Reference_To_Container_Wrapper
{
const Container& a_;
public:
explicit Reference_To_Container_Wrapper(const Container& a) : a_(a) {}
// (I) This line causes problems! This "Container" returned will be destroyed and cause troubles!
const Container get() const {return a_;} // Build a new Container out of the reference and return it
};
template <class T>
struct ReferenceContainer
{
T should_be_valid_lvalue_ref;
template <class U> // U = Reference_To_Container_Wrapper
ReferenceContainer(U&& u) :
// We store a l-value reference to a container, but the container is from line (I)
// and thus will soon get destroyed and we'll have a dangling reference
should_be_valid_lvalue_ref(Forward<T>(std::move(u).get())) {}
};
int main() {
Container a(42); // This lives happily with perfect valid data
ReferenceContainer<const Container&> rc( (Reference_To_Container_Wrapper(a)) ); // Parenthesis necessary otherwise most vexing parse will think this is a function pointer..
// rc now has a dangling reference
Container newContainer = rc.should_be_valid_lvalue_ref; // From reference to Container
newContainer.test();
return 0;
}
which outputs "OPS! A is destructed!"
if you just add a "&" in the line
const Container& get() const {return a_;}
the above works just fine.
http://ideone.com/SyUXss
I'm writing a network library and use move semantics heavily to handle ownership for file descriptors. One of my class wishes to receive file descriptor wrappers of other kinds and take ownership, so it's something like
struct OwnershipReceiver
{
template <typename T>
void receive_ownership(T&& t)
{
// taking file descriptor of t, and clear t
}
};
It has to deal multiple unrelated types so receive_ownership has to be a template, and to be safe, I wish it ONLY binds to rvalue references, so that user has to explicitly state std::move when passing an lvalue.
receive_ownership(std::move(some_lvalue));
But the problem is: C++ template deduction allows an lvalue to be passed in without extra effort. And I actually shot myself on the foot once by accidentally passing an lvalue to receive_ownership and use that lvalue(cleared) later.
So here is the question: how to make a template ONLY bind to rvalue reference?
You can restrict T to not be an lvalue reference, and thus prevent lvalues from binding to it:
#include <type_traits>
struct OwnershipReceiver
{
template <typename T,
class = typename std::enable_if
<
!std::is_lvalue_reference<T>::value
>::type
>
void receive_ownership(T&& t)
{
// taking file descriptor of t, and clear t
}
};
It might also be a good idea to add some sort of restriction to T such that it only accepts file descriptor wrappers.
A simple way is to provide a deleted member which accepts an lvalue reference:
template<typename T> void receive_ownership(T&) = delete;
This will always be a better match for an lvalue argument.
If you have a function that takes several arguments, all of which need to be rvalues, we will need several deleted functions. In this situation, we may prefer to use SFINAE to hide the function from any lvalue arguments.
One way to do this could be with C++17 and the Concepts TS:
#include <type_traits>
template<typename T>
void receive_ownership(T&& t)
requires !std::is_lvalue_reference<T>::value
{
// taking file descriptor of t, and clear t
}
or
#include <type_traits>
void receive_ownership(auto&& t)
requires std::is_rvalue_reference<decltype(t)>::value
{
// taking file descriptor of t, and clear t
}
Going slightly further, you're able to define a new concept of your own, which may be useful if you want to reuse it, or just for extra clarity:
#include <type_traits>
template<typename T>
concept bool rvalue = std::is_rvalue_reference<T&&>::value;
void receive_ownership(rvalue&& t)
{
// taking file descriptor of t, and clear t
}
Note: with GCC 6.1, you'll need to pass -fconcepts to the compiler, as it's an extension to C++17 rather than a core part of it.
Just for completeness, here's my simple test:
#include <utility>
int main()
{
int a = 0;
receive_ownership(a); // error
receive_ownership(std::move(a)); // okay
const int b = 0;
receive_ownership(b); // error
receive_ownership(std::move(b)); // allowed - but unwise
}
I learnt something that seems to confuse people quite often: using SFINAE is OK, but I can't use:
std::is_rvalue_reference<T>::value
The only way it works as I want is
!std::is_lvalue_reference<T>::value
The reason is: I need my function to receive an rvalue, not an rvalue reference. A function conditionally enabled with std::is_rvalue_reference<T>::value will not receive an rvalue, but rather receives an rvalue reference.
For lvalue references, T is deduced to be an lvalue reference, and for rvalue references, T is deduced to be a non-reference.
So if the function binds to a rvalue reference, what is seen at the end by the compiler for a certain type T is:
std::is_rvalue_reference<T>::value
and not
std::is_rvalue_reference<T&&>::value
Unfortunately, it seems like trying out is_rvalue_reference<TF> (where TF is the perfectly-forwarded type) does not work well if you are actually trying to make overloads that distinguish between const T& and T&& (e.g. using enable_if in both, one with is_rvalue_reference_v<TF> and the other with !is_rvalue_reference_V<TF>).
A solution (albeit hacky) is to decay the forwarded T, then place the overloads in a container aware of these types. Generated this example:
Hup, I was wrong, just forgot to look at Toby's answer (is_rvalue_reference<TF&&>) -- though it's confusing that you can do std::forward<TF>(...), but I guess that's why decltype(arg) also works.
Anywho, here's what I used for debugging: (1) using struct overloads, (2) using the wrong check for is_rvalue_reference, and (3) the correct check:
/*
Output:
const T& (struct)
const T& (sfinae)
const T& (sfinae bad)
---
const T& (struct)
const T& (sfinae)
const T& (sfinae bad)
---
T&& (struct)
T&& (sfinae)
const T& (sfinae bad)
---
T&& (struct)
T&& (sfinae)
const T& (sfinae bad)
---
*/
#include <iostream>
#include <type_traits>
using namespace std;
struct Value {};
template <typename T>
struct greedy_struct {
static void run(const T&) {
cout << "const T& (struct)" << endl;
}
static void run(T&&) {
cout << "T&& (struct)" << endl;
}
};
// Per Toby's answer.
template <typename T>
void greedy_sfinae(const T&) {
cout << "const T& (sfinae)" << endl;
}
template <
typename T,
typename = std::enable_if_t<std::is_rvalue_reference<T&&>::value>>
void greedy_sfinae(T&&) {
cout << "T&& (sfinae)" << endl;
}
// Bad.
template <typename T>
void greedy_sfinae_bad(const T&) {
cout << "const T& (sfinae bad)" << endl;
}
template <
typename T,
typename = std::enable_if_t<std::is_rvalue_reference<T>::value>>
void greedy_sfinae_bad(T&&) {
cout << "T&& (sfinae bad)" << endl;
}
template <typename TF>
void greedy(TF&& value) {
using T = std::decay_t<TF>;
greedy_struct<T>::run(std::forward<TF>(value));
greedy_sfinae(std::forward<TF>(value));
greedy_sfinae_bad(std::forward<TF>(value));
cout << "---" << endl;
}
int main() {
Value x;
const Value y;
greedy(x);
greedy(y);
greedy(Value{});
greedy(std::move(x));
return 0;
}
With more modern C++, we can simply require that T&& is an rvalue reference:
#include <type_traits>
template<typename T> requires std::is_rvalue_reference_v<T&&>
void receive_ownership(T&&)
{
// taking file descriptor of t, and clear t
}
Simple demonstration:
#include <string>
#include <utility>
int main()
{
auto a = std::string{};
auto const b = a;
receive_ownership(a); // ERROR
receive_ownership(std::move(a)); // okay
receive_ownership(b); // ERROR
receive_ownership(std::move(b)); // okay - but unwise!
receive_ownership(std::string{}); // okay
}