Replies: 26 comments 1 reply
-
Hi. This is by design. |
Beta Was this translation helpful? Give feedback.
-
On Scott Meyers excellent book Effective Modern C++, Item 25 states "Use std::move on rvalues references, std::forward on universal references" therefore not using universal references with forwarding does not move rvalues and is a mistake that can go undetected... let me come up with an example but please have this item in mind. |
Beta Was this translation helpful? Give feedback.
-
There is no mistake. The code is correct. Any function can accept argument by value. This ability exists from the beginning of C++ and does not produce any errors. The only difference with accepting argument by rvalue reference is that argument will be copied if you pass it as is and it will be created from rvalue reference (moved) if you pass argument enclosed inside |
Beta Was this translation helpful? Give feedback.
-
Let me explain you the difference in details:
void prepare_impl(Foo &&foo) {
//..
} and call Foo myFoo;
prepare_impl(std::move(myFoo)); then you pass initial
void prepare_impl(Foo foo) {
//..
} and call Foo myFoo;
prepare_impl(std::move(myFoo)); then you have a brand new object of type |
Beta Was this translation helpful? Give feedback.
-
Please listen carefully. I have a code that displays the error. Basically using forward in a template parameter that is not a universal reference makes the forwarding incorrect (it always calls the rvalue version): void makeLogEntry(std::string s) {}
struct Widget
{
int m_number;
Widget(int number) : m_number(number ) {}
};
void process( const Widget& lvalArg)
{
std::cout << "Handling lvalue\n";
}
void process(Widget&& rvalArg)
{
std::cout << "Handling rvalue\n";
}
template<typename T>
void LogAndProcessWithUR(T&& param)
{
makeLogEntry("calling processs");
process(std::forward<T>(param));
}
template<typename T>
void LogAndProcess(T param) // no universal reference
{
if (std::is_rvalue_reference_v<T>)
{
std::cout << "T is rvalue reference\n";
}
if (std::is_rvalue_reference_v<decltype(param)>)
{
std::cout << "param is rvalue reference\n";
}
makeLogEntry("calling processs");
process(std::forward<T>(param)); // ALWAYS forwards to process(Widget&&) regardless of the object passed
}
void testForwarding()
{
process(Widget{ 4 }); // call with rvalue
Widget w{ 5 };
process(w);
LogAndProcess(Widget{ 4 });
LogAndProcess(w);
LogAndProcessWithUR(Widget{ 4 });
LogAndProcessWithUR(w);
}
The result printed is: Handling rvalue See? Regards, |
Beta Was this translation helpful? Give feedback.
-
Are you aware that rvalue reference is not universal reference although both look the same? That is: void process(Widget&& rvalArg) // rvalue reference, should be moved
{
std::cout << "Handling rvalue\n";
}
template<typename T>
void LogAndProcessWithUR(T&& param) // universal reference: Not rvalue reference!!
{
makeLogEntry("calling processs");
process(std::forward<T>(param));
} |
Beta Was this translation helpful? Give feedback.
-
Ok I see that |
Beta Was this translation helpful? Give feedback.
-
param is always copied in LogAndProcess and therefore std::forward is equivalent to std::move.. we end up moving the copied object - but it is copied once! While LogAndProcessWithUR receives the lvalue or rvalue and forces no copy. |
Beta Was this translation helpful? Give feedback.
-
Yes it is copied once in your case. But if you change |
Beta Was this translation helpful? Give feedback.
-
I agree, but then we are making all objects rvalues even if they aren't! Isn't this a problem? |
Beta Was this translation helpful? Give feedback.
-
Probably. Please show me the problem. All I can see is that it can be a problem if you have two overloads like Also Scott Meyers said that we need to use |
Beta Was this translation helpful? Give feedback.
-
the only problem I see is that the lvalue is emptied upon std::move and should be not used anymore... like so: process(Widget{ 4 }); // call with rvalue
Widget w{ 5 };
process(w);
LogAndProcess(Widget{ 4 });
LogAndProcess(std::move(w)); // w is erased
LogAndProcessWithUR(Widget{ 4 });
LogAndProcessWithUR(w); // cannot use w here!
|
Beta Was this translation helpful? Give feedback.
-
why is it a problem? I mean when you have a code like this: void bar(std::string argument) {
//..
}
std::string myString = "some content"
bar(move(myString)); you also think that it has a problem? |
Beta Was this translation helpful? Give feedback.
-
I see now that you have an idiom in your code... if you always call std::move before sending the parameter to a template function then you are correct: this is no problem! But the only thing that I still feel is incorrect (call it misleading if you want) is the call to std::forward inside the template since it will always succeed in casting to rvalue (rather call std::move I think). |
Beta Was this translation helpful? Give feedback.
-
I don't want to eliminate the option of copying of object in case it is required. Accepting argument by value is a universal way of accepting argument cause it can be used for both copying (sometimes developers copy arguments by design) and moving. |
Beta Was this translation helpful? Give feedback.
-
yes but what about the misleading std::forward? it ALWAYS casts to rvalue when the template receives by value?? So it is not forwarding at all! It is "moving the value parameter" |
Beta Was this translation helpful? Give feedback.
-
this is no mistake - it just is a bit non-documenting the intention... |
Beta Was this translation helpful? Give feedback.
-
I use |
Beta Was this translation helpful? Give feedback.
-
I think if std::forward Always moves then std::move should be used - the intention is clearer. |
Beta Was this translation helpful? Give feedback.
-
maybe I am being pedantic, if so I am sorry. I just like your library so much it deserves the best and most clear wording! |
Beta Was this translation helpful? Give feedback.
-
It is the same. I mean that I use |
Beta Was this translation helpful? Give feedback.
-
Everything is ok. You are doing a great job. Thank you for taking care of it! I appreciate it! |
Beta Was this translation helpful? Give feedback.
-
You are very welcome! By the way I may be writing an article for a Costa Rican magazine related to using your amazing library and how it becomes so high-level and declarative by mixing C++ with SQL!! I will let you know if that project falls thru... |
Beta Was this translation helpful? Give feedback.
-
there is no wiki user guide only the text in your github site? |
Beta Was this translation helpful? Give feedback.
-
I started using triggers!!! Wow what a great addition! |
Beta Was this translation helpful? Give feedback.
-
There is a short wiki on GitHub at Wiki tab also |
Beta Was this translation helpful? Give feedback.
-
Hi,
I thought applying forward required that S was declared a universal reference like so:
you apply:
shouldn't you have:
instead of
but you don't do it... is this a coding error? or am I mistaken?
Regards,
Juan
Beta Was this translation helpful? Give feedback.
All reactions